Thank you for choosing keyestudio!
We will endeavour to provide you with better products and services!
About keyestudio
Keyestudio is the best-selling brand owned by KEYES Corporation. Our product contains Arduino development and expansion boards, sensors and modules, Raspberry Pi, micro:bit expansion boards as well as smart cars and learning kits, which can help customers at any level to learn about Arduino.
Notably, all of our products are in line with international quality standards and are greatly appreciated in a broad menu of different markets across the world.
Welcome to check out more contents from our official website: http://www.keyestudio.com
Obtain Information and After-sales Service
If something is found missing or broken, or you have some difficulty learning the kit, please feel free to contact us. Welcome to send email to us: service@keyestudio.com
We will endeavour to update projects and products continuously from your sincere advice! Thanks!
Warning
This product contains tiny pin headers, so please keep out of reach of children under 7 to prevent from lacerations.
This product also contains conductive parts(control board and electronic modules). Please operate according to the requirements of tutorials. Otherwise, improper operation may damage parts due to overheating. In this case, do not touch it and immediately disconnect the circuit power.
Copyright
The Keyestudio trademark and logo are the copyright of KEYES DIY ROBOT co.,LTD. All products under Keyestudio brand can’t be copied, sold or resold without authorization by anyone or any company. If you are interested in our products, please contact to our sales representatives: fennie@keyestudio.com
Keyestudio IOT Learning Kit for ESP32
Introduction
Welcome to Keyestudio ESP-32 IOT Learning Kit! This kit is designed for beginners and developers with an insight into the versatile world of ESP-32 microcontrollers. With ESP-32 WROOM 32 at its core, it includes components such as leds, sensors, and motor. Thus, users can explore a wide variety of DIY and IoT projects.
Whether you’re keen on basic electronics or IoT integration, this kit covers what you want. It not only provides IDE setup and basic syntax of MicroPython, but also covers those of Arduino with a dedicated section on fun DIY and projects.
In this kit, each project is carefully outlined to ensure you understand the objectives, circuit assembly, programming and code interpretation. Beyond that, actual application programs and troubleshooting FAQs are contained to provide a rich learning experience for all. Let’s start the games and IoT projects with ESP-32!
In addition, if you have any difficulties or questions about this tutorial and kit, please contact us at any time.
Kit List
Please check the list to ensure that all parts are intact. If you find missing ones, please contact our sales staff immediately.
# |
PIC |
NAME |
QTY |
---|---|---|---|
1 |
ESP32 PLUS main control board |
1 |
|
2 |
breadboard |
1 |
|
3 |
ultrasonic sensor |
1 |
|
4 |
stepper motor drive board |
1 |
|
5 |
PIR motion sensor |
1 |
|
6 |
RFID module |
1 |
|
7 |
joystick module |
1 |
|
8 |
LCD_128X32_DOT module |
1 |
|
9 |
thin film 4*4 key pad |
1 |
|
10 |
servo |
1 |
|
11 |
stepper motor |
1 |
|
12 |
DC motor |
1 |
|
13 |
1-bit digital tube |
1 |
|
14 |
4-bit digital tube |
1 |
|
15 |
relay module |
1 |
|
16 |
DHT11 temperature and humidity sensor |
1 |
|
17 |
LM35 temperature sensor |
1 |
|
18 |
sound sensor |
1 |
|
19 |
OLED module |
1 |
|
20 |
button |
4 |
|
21 |
passive buzzer |
1 |
|
22 |
active buzzer |
1 |
|
23 |
photoresistor |
2 |
|
24 |
tilt switch |
1 |
|
25 |
flame sensor |
1 |
|
26 |
thermistor |
1 |
|
27 |
IR receiver |
1 |
|
28 |
74HC595 chip |
1 |
|
29 |
potentiometer |
1 |
|
30 |
NPN(S8050) transistor |
2 |
|
31 |
PNP(S8550) transistor |
2 |
|
32 |
RGB LED |
1 |
|
33 |
red LED |
10 |
|
34 |
yellow LED |
10 |
|
35 |
green LED |
10 |
|
36 |
blue LED |
10 |
|
37 |
220Ω resistor |
10 |
|
38 |
10KΩ resistor |
10 |
|
39 |
1KΩ resistor |
10 |
|
40 |
battery holder |
1 |
|
41 |
IC card |
1 |
|
42 |
ID card |
1 |
|
43 |
joystick cap |
1 |
|
44 |
fan |
1 |
|
45 |
resistance card |
1 |
|
46 |
remote control |
1 |
|
47 |
yellow button cap |
4 |
|
48 |
Micro USB cable |
1 |
|
49 |
jumper wire |
1 |
|
50 |
F-F DuPont wire |
1 |
|
51 |
M-F DuPont wire |
1 |
|
52 |
1.5V AA battery (self-provided) |
6 |
Resource Download
Click to download to all resources such as project codes and libraries.
ESP32 Main Control Board
For details, please visit: https://docs.keyestudio.com/projects/KS5016
Troubleshooting Guide
Q: Error occurs during burning code on ESP32 main board?
A: Please check whether the ESP32 board model and the USB serial port number is correct.
Q: The serial port is not displayed after ESP32 connects to computer via Micro USB cable?
A: Please check whether the ESP32 board is properly connected to the computer. Click “Device Manager” to check whether the corresponding serial port is displayed. If the port number is correct, the connection is intact, if not, there may be a problem with the USB chip on ESP32 board.
Q: After burning code, sensors/modules do not work or the serial monitor shows nothing?
A: Please ensure the connected pin is in accordance with the code. If it is not, codes prevail.
Q: Servo works out of order?
A: The power voltage may be insufficient. Try to connect to an external power supply.
Q: The distance detected by the ultrasonic sensor is inaccurate?
A: The distance is detected from the emitter. This module is not a high-precision one, so differences exist.
Q: Fan(motor) works out of order to burn the main board?
A: When the fan is working, the required current is larger than that of other sensors, which may cause voltage and current fluctuations in the circuit. Especially when the fan is rotating forward to backward, the fluctuations are so large that the voltage and current of the ESP32 board is very low, thus being reset. An external power supply is required for the ESP32 board to ensure that the fans can work properly.
Q: The tone played by the passive buzzer is not conform with actual intonation pitch?
A: The common passive buzzer can not meet the requirements of professional tones. If you need very accurate pitch, a more professional buzzer should be adopted.
Q: False alarm happens on the PIR motion sensor?
A: To avoid false alarm, requirements are as follows:
Away the detection range from blowing objects caused by the wind, such as curtains, clothing and flowers.
Away the detection range from interference of strong light irradiation, including sunlight, car light and spotlight.
Q: Is the temperature and humidity sensor waterproof?
A: The sensor detects the temperature and humidity in the air, rather than water. It is not waterproof so please do not directly put it into water.
Q: OLED module does not light up after powering on?
A: OLED does not include a backlight and is self-lighting mode. OLED will not light when only connecting to VCC and GND. It must be programmed to light up.
Q: WiFi connection always fails?
A: Please put the ESP32 WiFi board around the router, press the on-board reset button, and wait for the connection. If it still can’t connect, please check whether the WiFi name and passwords are correct.
Q: The response is slow when remote-controlling sensors through web page?
A: Causes of slow transmission on router network:
If multiple users are connected and the CPU resources of the router are insufficient, restart the router and reconnect to the network.
If the router is used for a long time, restart it.
There is wireless interference. Wireless signals are unstable, so please do not use through walls.
For more router related knowledge, please Google.
1. Arduino_C Tutorial
1-1 About Arduino IDE
1-1-1 Install Arduino IDE(Important)
Arduino IDE provides all the software needed to complete Arduino projects, which allows us to write programs and upload them to the Arduino board.
Arduino IDE 2.3.3 is published as an open source tool and is improved based on Arduino IDE 1.x. It comes with improved user interfaces, boards and library managers, debuggers, auto-complete capabilities, etc.
In this tutorial, we will demonstrate how to download and install Arduino IDE 2.3.3 on a Windows, MacOS, or Linux computer.
⚠️ATTENTION: In this tutorial, we use Arduino IDE 2.3.3. Other versions may not be compatible.
Requirement
Windows - Win 10 or later versions, 64 bit
Linux - 64 bit
MacOS - 64 bit
Download
1. access Arduino IDE 2.3.3
2. download the IDE version that is compatible with your computer.
⚠️NOTE: Arduino IDE version updates fast and advanced versions may fail to compile codes. Therefore, we provide the Arduino IDE 2.3.3 package.
Installation
Windows
1. Click arduino-ide_xxxx.exe file to execute the file.
2. Read license agreement and click “I Agree”.
3. Tick “Anyone who uses this conputer(all users)”, and “Next”.
4. Choose an installation path and click “Install”.
5. “Finish”.
MacOS:
Download arduino_ide_xxxx.dmg , and copy Arduino IDE.app to Applications file to install the Arduino IDE.
Linux:
For how to install Arduino IDE 2.3.3 on Linux, please refer to: https://docs.arduino.cc/software/ide-v2/tutorials/getting-started/ide-v2-downloading-and-installing/#linux
Enablement
1. Open Arduino IDE 2.3.3 and it will install Arduino AVR board and built-in libraries automatically.
2. The firewall or Security Centres may pop up some windows asking if you want to install drivers. Please install.
3. Now the Arduino IDE is ready!
⚠️ATTENTION: If some installations don’t work due to issues like poor network, re-open Arduino IDE to complete the rest of the installation. After that, “Output” does not open automatically unless you click “Verify” or “Upload”.
1-1-2 Install Driver(Important)
A driver is required to enable the ESP32 main board. Otherwise, there will be no COM port to be connected on the computer.
How to install driver: https://docs.keyestudio.com/projects/Arduino/en/latest/Arduino%20IDE%20Tutorial.html#install-driver
Enter the corresponding guide according to ESP32 board and operating system.
1-1-3 Arduino IDE Toolbar
1. Verify - compiles your code to your Arduino Board.
2. Verify / Upload - compiles and uploads your code to your Arduino Board. The on-board RX and TX LED quickly flash until uploading finishes.
3. Debugger - test and debug programs in real time.
4. Select Board - choose board and port.
5. Serial Plotter - displays serial data in a method of line graph
6. Serial Monitor - opens the Serial Monitor tool, as a new tab in the console.
7. File - includes new Sketch, open Sketch, open recently used code, open sample code, close the IDE, save code, preferences, advanced Settings, etc.
8. Edit - includes copy, paste, automatic formatting, font size, etc. (shortcut keys are recommended).
9. Sketch - includes verify\compile, upload code, import library and so on.
10. Tools - The most important two are development board and port. They must be set before uploading code.
11. Help - Views the IDE version and official reference documents.
12. Output Bar - alter output.
13. IDE prompt area -Uploading fails or succeeds & Serial monitor display area.
14. Board & Port - preview board model and port. You may re-set in “Tools → Board / Port”.
15. Code editing area
16. Sketchbook - here you will find all of your sketches locally stored on your computer.
17. Boards Manager - install or remove Arduino Boards.
18. Library Manager - browse through thousands of Arduino libraries or import local libraries.
19. Debugger - test and debug programs in real time.
20. Search - search for keywords in your code.
1-1-4 Install ESP32 Board(Important)
ESP32 board needs to be installed in Arduino IDE before using.
Install ESP32
1. Click “File → Preferences”.
2. Add the link:https://espressif.github.io/arduino-esp32/package_esp32_index.json in Additional boards manager URLs and click OK.
3. Select the icon of board manager to search for “ESP32” and click version 1.06 to “Install”. (⚠️Note that here we adopt 1.06 version of the ESP32. Installation may fail if you choose later versions.)
3. Now the ESP32 is installed.
Upload Code
1. Connect ESP32 WROOM 32 to your computer via Micro USB cable.
2. Click “Tools” → “Board” → “esp32” to choose ESP32 Dev Module.
3. After connecting, click “Tools” → “Port”.
4. For ESP32, you need to click “Select other board and port” to set them manually.
5. Search “ESP32 Dev Module” and click “OK”.
6. After that, you can choose them easily. Yet, at next time, ESP32 may be not accessed in it, so just set them again.
7. Now its ready for uploading code to ESP32.
1-1-5 Import Arduino Library(Important)
Libraries are a collection of pre-written code or functions that extend the functionality of the Arduino IDE, so that they allow you to save time and effort to code complex functions.
⚠️ATTENTION: Please import the libraries we provided! Manual import is recommended!
Method One: Manual Import
Except for Arduino library manager, you may import your own library manually.
1. Click Sketch → Include Library → Add .ZIP Library….
2. Locate in …\ Library \ Arduino_Library file and choose library zips to “Open”.
3. After that, you will see “Library installed”. You can use this library directly next time you need it.
4. Import the rest libraries as well.
Method Two: Library Manager
There are many libraries are included in “Arduino Library Manager”.
1. In Library Manager, search for the desired library by name or browse different categories.
⚠️ATTENTION: Prompts are written in projects that require libraries. For example, “Herein, Adafruit_GFX library is included. Please install it in Library Manager.”
2. Find the library and Install. If “INSTALL WITHOUT DEPENDENCIES” and “INSTALL ALL” appears, choose “INSTALL ALL”. So do the other libraries.
3. Arduino IDE downloads the library automatically.
4. Other libraries are the same.
Path to Library
If you installed the library using the above method, it is in the default library directory of the Arduino IDE: C:\Users\xxx\Documents\Arduino\libraries.
If not, enter “File” → “Preferences” to check the path.
For details, please visit: Installing libraries in Arduino IDE 2
1-2 IoT Projects
The ESP32 iot Learning Kit utilizes the ESP32-S3 WiFi and Bluetooth to support a variety enjoyable IoT projects. Here we provide a tutorial to do these projects.
WiFi connectivity allows you to connect the Arduino to the Internet and cloud platforms. With WiFi, you can build projects like simple Web servers to remotely control leds, or Arduino IoT Cloud interactions to monitor sensors.
As for Bluetooth, it supports localized(short-range) wireless communication, including Bluetooth control LED, relay, RGB and buzzer. We pair the ESP32 with your smartphone or other Bluetooth-enabled device to perform a variety of control and monitoring tasks.
1-2-01 IoT Bluetooth
1. Overview
In this experiment, we develop a simple Bluetooth Low Power (BLE) serial communication application with an ESP32 microcontroller. The ESP32 integrates Wi-Fi and Bluetooth, making it ideal for developing wireless applications. BLE is a low power wireless communication protocol designed for short distance communication.
This project covers the steps to set up the ESP32 as a BLE server and communicate with BLE clients over a serial connection.
2. Components
ESP32 main board x1 |
Micro USB cable x1 |
mobile device x1 |
3. Component Knowledge
The ESP32 WROOM 32 integrates Wi-Fi and Bluetooth. It supports Bluetooth Low Energy (BLE) and Classic Bluetooth protocols and can be used as a Bluetooth client or server. As a Bluetooth client, it can connect to other Bluetooth devices and exchange data with them. As a Bluetooth server it provides services to other devices.
The module supports several Bluetooth profiles, including Generic Access Profile (GAP), Generic Attribute Profile (GATT), and Serial Port Profile (SPP). The SPP allows the module to emulate a serial port over Bluetooth, enabling serial communication with other Bluetooth devices.
When using the Bluetooth of the ESP32 WROOM 32, we need to program with an appropriate software development kit (SDK) or an Arduino IDE with the ESP32 BLE library that provides advanced interfaces for BLE, including an example of how to use the module as a BLE client and server.
Bluetooth is a short-distance communication system that can be divided into two types, namely low power bluetooth (BLE) and classic bluetooth. There are two modes for simple data transfer: master mode and slave mode.
Master Mode: In this mode, work is done on the master device and can be connected to the slave device. When the device initiates a connection request in the main mode, information such as the address and pairing password of other bluetooth devices are required. Once paired, you can connect directly to them.
Slave Mode: A bluetooth module in the slave mode can only accept connection requests from the host, but cannot initiate connection requests. After being connected to a host device, it can send and receive data through the host device . Bluetooth devices can interact with each other, when they interact, the bluetooth device in the main mode searches for nearby devices. While a connection is established, they can exchange data. For example, when a mobile phone exchanges data with ESP32, the mobile phone is usually in master mode and the ESP32 is in slave mode.
Overall, the Bluetooth capability of the ESP32 WROOM 32 provides a convenient and low-power way to enable wireless communication in the project.
4. Wiring Diagram
5. Download and install LightBlue APP
Take a tablet or smartphone, click App Store (iOS users) or Google Play (Android users) to download LightBlue. Or directly search “LightBlue” in App Store(iOS users) or Google Play(Android users) to download the APP.
Here we take Android system as an example, and iOS users may have a reference.
6. Test Code
/*
* Filename: IoT_Bluetooth
* Function: Bluetooth data transfer
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEUtils.h"
#include "BLE2902.h"
// Define the Bluetooth device name
const char *bleName = "ESP32_Bluetooth";
// Define the received text and the time of the last message
String receivedText = "";
unsigned long lastMessageTime = 0;
// Define the UUIDs of the service and characteristics
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Define the Bluetooth characteristic
BLECharacteristic *pCharacteristic;
void setup() {
Serial.begin(115200); // Initialize the serial port
setupBLE(); // Initialize the Bluetooth BLE
}
void loop() {
// When the received text is not empty and the time since the last message is over 1 second
// Send a notification and print the received text
if (receivedText.length() > 0 && millis() - lastMessageTime > 1000) {
Serial.print("Received message: ");
Serial.println(receivedText);
pCharacteristic->setValue(receivedText.c_str());
pCharacteristic->notify();
receivedText = "";
}
// Read data from the serial port and send it to BLE characteristic
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
const char *newValue = str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
// Define the BLE server callbacks
class MyServerCallbacks : public BLEServerCallbacks {
// Print the connection message when a client is connected
void onConnect(BLEServer *pServer) {
Serial.println("Connected");
}
// Print the disconnection message when a client is disconnected
void onDisconnect(BLEServer *pServer) {
Serial.println("Disconnected");
}
};
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
// When data is received, get the data and save it to receivedText, and record the time
std::string value = std::string(pCharacteristic->getValue().c_str());
receivedText = String(value.c_str());
lastMessageTime = millis();
Serial.print("Received: ");
Serial.println(receivedText);
}
};
// Initialize the Bluetooth BLE
void setupBLE() {
BLEDevice::init(bleName); // Initialize the BLE device
BLEServer *pServer = BLEDevice::createServer(); // Create the BLE server
// Print the error message if the BLE server creation fails
if (pServer == nullptr) {
Serial.println("Error creating BLE server");
return;
}
pServer->setCallbacks(new MyServerCallbacks()); // Set the BLE server callbacks
// Create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Print the error message if the BLE service creation fails
if (pService == nullptr) {
Serial.println("Error creating BLE service");
return;
}
// Create the BLE characteristic for sending notifications
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902()); // Add the descriptor
// Create the BLE characteristic for receiving data
BLECharacteristic *pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks()); // Set the BLE characteristic callbacks
pService->start(); // Start the BLE service
pServer->getAdvertising()->start(); // Start advertising
Serial.println("Waiting for a client connection..."); // Wait for a client connection
}
7. Test Result
Please follow the steps below:
1. Open the file IoT_Bluetooth.ino in …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-01 IoT Bluetooth , Or copy and paste the above test code into the Arduino IDE.
2. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
3. After uploading code, enable Bluetooth on your mobile device (smartphone) and open LightBlue.
4. In Peripherals, find ESP32-Bluetooth and click “Connect”. If you don’t see it, try refreshing the page a few times. Once “Connected”, the Bluetooth is connected. Scroll down to set 3 UUIDs in the code. And Arduino IDE serial monitor shows “Connected”.
(⚠️ATTENTION: On iOS devices, if the LightBlue APP you downloaded and installed is an older version, find MPY ESP32 and click “Connect”. If LightBlue is a new version, find ESP32-Bluetooth and click “Connect”. Other operations are similar to Android system.)
5. Tap Receive UUID and “HEX” to enter Format Selection , choose “UTF-8 String” to “Save”. For instance, “HEX” is hexadecimal; “ UTF-8 String ” is character; “Binary” is binary; and so on.
6. Click “Subscribe” and it changes into “Unsubscribe”.
7. Open the serial monitor and set the baud rate to “115200”. Enter “welcome” and tap “Enter”.
8. And “welcome” will be displayed on LightBlue.
9. To send information from a mobile device to the serial monitor, tap Send UUID and “HEX” to enter Format Selection and choose “UTF-8 String” to “Save”.
10. Click “Write New Value” to enter “bluetooth test” and click “Write”.
11. The “Serial Monitor” shows messages.
8. Code Explanation
This code is written for the ESP32 microcontroller and is set to communicate with Bluetooth Low Energy (BLE) devices. Here is a brief summary of the code:
Necessary libraries: first include the libraries required to use Bluetooth Low Energy (BLE) on the ESP32.
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEUtils.h"
#include "BLE2902.h"
Global Variables: define a set of global variables, including the Bluetooth device name(
bleName
), UUID of variables, services, and characteristics used to track when the text and last message were received, andBLECharacteristic
instance(pCharacteristic
).
// Define the Bluetooth device name
const char *bleName = "ESP32_Bluetooth";
// Define the received text and the time of the last message
String receivedText = "";
unsigned long lastMessageTime = 0;
// Define the UUIDs of the service and characteristics
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Define the Bluetooth characteristic
BLECharacteristic *pCharacteristic;
Initialization:
setup()
sets baud rate to 115200;setupBLE()
initializes BLE.
void setup() {
Serial.begin(115200); // Initialize the serial port
setupBLE(); // Initialize the Bluetooth BLE
}
Main Loop: in
loop()
, If the string is received via BLE (i.e. receivedText is not empty) and at least 1 second has passed since the last message, the code prints the received string to the serial monitor. SetCharacteristic
to the received string, and send the notification, and then clear the received string. If there is data available on the serial port, it reads the string until it encounters a newline. Set the feature value to this string and send the notification.
void loop() {
// When the received text is not empty and the time since the last message is over 1 second
// Send a notification and print the received text
if (receivedText.length() > 0 && millis() - lastMessageTime > 1000) {
Serial.print("Received message: ");
Serial.println(receivedText);
pCharacteristic->setValue(receivedText.c_str());
pCharacteristic->notify();
receivedText = "";
}
// Read data from the serial port and send it to BLE characteristic
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
const char *newValue = str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
Callback: Two callback classes(
MyServerCallbacks
andMyCharacteristicCallbacks
) are used to handle events related to Bluetooth communication.MyServerCallbacks
handles issues related to the connection status (connected or disconnected) of the BLE server, whileMyCharacteristicCallbacks
handles write issues on BLE features, i.e. when a connected device sends a string to the ESP32 via BLE, the string is captured and stored inreceivedText
, and the current time is recorded inlastMessageTime
.
// Define the BLE server callbacks
class MyServerCallbacks : public BLEServerCallbacks {
// Print the connection message when a client is connected
void onConnect(BLEServer *pServer) {
Serial.println("Connected");
}
// Print the disconnection message when a client is disconnected
void onDisconnect(BLEServer *pServer) {
Serial.println("Disconnected");
}
};
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
// When data is received, get the data and save it to receivedText, and record the time
std::string value = std::string(pCharacteristic->getValue().c_str());
receivedText = String(value.c_str());
lastMessageTime = millis();
Serial.print("Received: ");
Serial.println(receivedText);
}
};
Set BLE:
setupBLE()
is used to initialize BLE devices and servers, set server callbacks, create BLE services with defined UUids, create features for sending notifications and receiving data and add them to services, and set feature callbacks. Finally, the service starts and the server begins broadcasting.
// Initialize the Bluetooth BLE
void setupBLE() {
BLEDevice::init(bleName); // Initialize the BLE device
BLEServer *pServer = BLEDevice::createServer(); // Create the BLE server
// Print the error message if the BLE server creation fails
if (pServer == nullptr) {
Serial.println("Error creating BLE server");
return;
}
pServer->setCallbacks(new MyServerCallbacks()); // Set the BLE server callbacks
// Create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Print the error message if the BLE service creation fails
if (pService == nullptr) {
Serial.println("Error creating BLE service");
return;
}
// Create the BLE characteristic for sending notifications
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDecodeor(new BLE2902()); // Add the decodeor
// Create the BLE characteristic for receiving data
BLECharacteristic *pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks()); // Set the BLE characteristic callbacks
pService->start(); // Start the BLE service
pServer->getAdvertising()->start(); // Start advertising
Serial.println("Waiting for a client connection..."); // Wait for a client connection
}
⚠️ATTENTION: This code allows two-way communication - it can send and receive data via BLE. However, to interact with specific hardware (such as leds on and off), additional code should be added to process the received string and act accordingly.
1-2-02 IoT Bluetooth Control LED
1. Overview
This project is an extension of the previous one, adding LED configuration and custom commands such as “led_on” and “led_off”. These commands allow you to control the on and off of the LED by sending commands from LightBlue APP on your mobile device.
2. Component Knowledge
LED
An LED is a semiconductor known as a “light-emitting diode”, which is made of semiconductor materials (silicon, selenium, germanium, etc.). It is polar. The short pin is negative that connects to GND, while the long one is positive that connects to 3.3V or 5V.
Here is the detailed introduction for the LED: LED - Wikipedia
Five-color-ring Resistor
A resistor limits or regulates the flow of current in the circuit. The left picture is the appearance of the resistor and the right one is its circuit symbol. Its unit of R is ohm(Ω). 1 MΩ= 1000 kΩ, 1 kΩ = 1000Ω.
We can use resistors to protect sensitive components, like LED. The resistance(Ω) is marked on the body with an electronic color code. Each color represents a number, and you can refer to it in the resistance card.
-ring 1 – 1st Digit. -ring 2 – 2nd Digit. -ring 3 – 3rd Digit. -ring 4 – Multiplier. -ring 5 – Tolerance.
In this kit, we provide four five-color-ring resistor. Here we take three of them as examples.
220Ω resistor *10
10KΩ resistor *10
1KΩ resistor *10
You can learn more about resistor from Wiki: Resistor - Wikipedia
In the same voltage, there will be less current but more resistance. The connection between current(I), voltage(V), and resistance® can be expressed: I=U/R. In the figure below, for instance, if the voltage is 3V, the current through R1 equals I = U / R = 3 V / 10 KΩ= 0.0003A= 0.3mA.
You can learn more about Ohm’s Law from Wiki: Ohm’s Law - Wikipedia
Don’t connect a low resistance directly to the two poles of the power supply, as this will cause excessive current to damage the electronic components. Resistors are nonpolar.
Breadboard
Breadboards are used to build and test circuits quickly before completing any circuit design. There are many holes in the breadboard so that components such as resistors can be inserted into it. A typical breadboard is shown below:
The breadboard comes with many metal strips that run underneath the board to connect holes together. They are laid out as shown below. Note that the top and bottom rows of holes are connected horizontally, while the remaining holes are connected vertically.
The first two rows (top) and the last two rows (bottom) are used for power positive(+) and negative(-) respectively. The conductive layout is shown below:
We should know that the up and low holes of groove in the middle are not connected. So we can connect the DIP(Dual in-line Packages) components (say, integrated circuits, microcontrollers, chips, etc.) as shown below:
If you want to know more about breadboard, refer to: How to Use a Breadboard - Science Buddies
3. Components
ESP32 main board x1 |
red LED x1 |
220Ω resistor x1 |
mobile device x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
4. Wiring Diagram
We adopt digital pin IO26 in this experiment. In the circuit, we connect a 220Ω resistor in serial, which protect the LED from over-current.
Schematic diagram:
Wiring diagram:
5. Download and install the LightBlue APP:
⚠️Note: if you have downloaded and installed the LightBlue APP in the previous lesson 1-2-01, you can skip this step; Otherwise, follow the instructions in lesson 1-2-01 to download and install the LightBlue APP
6. Test Code
/*
* Filename: IoT_Bluetooth Control LED
* Function: Bluetooth + APP control LED
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEUtils.h"
#include "BLE2902.h"
const int ledPin = 26; // Define LED pin to IO26.
// Define the Bluetooth device name
const char *bleName = "ESP32_Bluetooth";
// Define the received text and the time of the last message
String receivedText = "";
unsigned long lastMessageTime = 0;
// Define the UUIDs of the service and characteristics
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Define the Bluetooth characteristic
BLECharacteristic *pCharacteristic;
void setup() {
Serial.begin(115200); // Initialize the serial port
setupBLE(); // Initialize the Bluetooth BLE
pinMode(ledPin, OUTPUT); // Set LED pin to output
}
void loop() {
// When the received text is not empty and the time since the last message is over 1 second
// Send a notification and print the received text
if (receivedText.length() > 0 && millis() - lastMessageTime > 1000) {
Serial.print("Received message: ");
Serial.println(receivedText);
pCharacteristic->setValue(receivedText.c_str());
pCharacteristic->notify();
receivedText = "";
}
// Read data from the serial port and send it to BLE characteristic
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
const char *newValue = str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
// Define the BLE server callbacks
class MyServerCallbacks : public BLEServerCallbacks {
// Print the connection message when a client is connected
void onConnect(BLEServer *pServer) {
Serial.println("Connected");
}
// Print the disconnection message when a client is disconnected
void onDisconnect(BLEServer *pServer) {
Serial.println("Disconnected");
}
};
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = std::string(pCharacteristic->getValue().c_str());
if (value == "led_on") {
digitalWrite(ledPin, HIGH); // LED on.
Serial.println("LED turned on");
} else if (value == "led_off") {
digitalWrite(ledPin, LOW); // LED off.
}
}
};
// Initialize the Bluetooth BLE
void setupBLE() {
BLEDevice::init(bleName); // Initialize the BLE device
BLEServer *pServer = BLEDevice::createServer(); // Create the BLE server
// Print the error message if the BLE server creation fails
if (pServer == nullptr) {
Serial.println("Error creating BLE server");
return;
}
pServer->setCallbacks(new MyServerCallbacks()); // Set the BLE server callbacks
// Create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Print the error message if the BLE service creation fails
if (pService == nullptr) {
Serial.println("Error creating BLE service");
return;
}
// Create the BLE characteristic for sending notifications
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902()); // Add the descriptor
// Create the BLE characteristic for receiving data
BLECharacteristic *pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks()); // Set the BLE characteristic callbacks
pService->start(); // Start the BLE service
pServer->getAdvertising()->start(); // Start advertising
Serial.println("Waiting for a client connection..."); // Wait for a client connection
}
7. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-02 IoT Bluetooth Control LED , open file IoT_Bluetooth_Control_LED.ino , or copy and paste the above test code into the Arduino IDE.
2. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
3. After uploading code, enable Bluetooth on your mobile device (smartphone) and open LightBlue.
4. In Peripherals, find ESP32-Bluetooth and click “Connect”. If you don’t see it, try refreshing the page a few times. Once “Connected”, the Bluetooth is connected. Scroll down to set 3 UUIDs in the code. And Arduino IDE serial monitor shows “Connected”.
(⚠️ATTENTION: On iOS devices, if the LightBlue APP you downloaded and installed is an older version, find MPY ESP32 and click “Connect”. If LightBlue is a new version, find ESP32-Bluetooth and click “Connect”. Other operations are similar to Android system.)
5. Tap Send UUID and “HEX” to enter Format Selection , choose “UTF-8 String” to “Save”.
6. Click “Write New Value” to edit commands. Now try to send the command: “led_on” to check whether LED responses to this command. Input “led_on” and click “Write” to see whether LED lights up. At the same time, the serial monitor prints the corresponding messages.
7. Click “Write New Value” to edit commands. Now try to send the command: “led_off” to check whether LED responses to this command. Input “led_off” and click “Write” to see whether LED turns off. At the same time, the serial monitor prints the corresponding messages.
8. Code Explanation
This project is an extension of the previous one, adding LED configuration and custom commands such as “led_on” and “led_off”. These commands allow you to control the on and off of the LED by sending commands from LightBlue APP on your mobile device.
Let’s explain the code in details:
Add a new global variable to the LED pin.
const int ledPin = 26; // Define LED pin to IO26.
setup()
set LED pin to output.
pinMode(ledPin, OUTPUT); // Set LED pin to output
Modify onWrite method in class
MyCharacteristicCallbacks
. This function listens for data coming from the Bluetooth connection and controls LED according to the received string (such as “led_on” and “led_off”).
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = std::string(pCharacteristic->getValue().c_str());
if (value == "led_on") {
digitalWrite(ledPin, HIGH); // LED on.
Serial.println("LED turned on");
} else if (value == "led_off") {
digitalWrite(ledPin, LOW); // LED off.
Serial.println("LED turned off");
}
}
};
1-2-03 IoT Bluetooth Control Buzzer
1. Overview
In previous experiments, we have learned how Bluetooth transmits data and controls LED. Here we configure buzzer to set custom commands such as “buzzer_on” and “buzzer_off”. These commands allow you to control the buzzer to emit sound by sending commands from LightBlue APP on your mobile device.
2. Component Knowledge
Active buzzer
In the active buzzer, a simple oscillator circuit is integrated to convert constant direct current into pulse signals with a certain frequency. Once it receives a high level, it will emit sound.
However, passive buzzer is without vibration source, so it must be driven by 2k ~ 5k square waves, rather than a DC signal.
They are very similar in appearance, but the passive one buzzer is with a green circuit board, while the active one is with black tape. Passive buzzers are not polar, yet active ones are.
You can learn more about buzzer from Wiki: Buzzer - Wikipedia
Transistor
As buzzer requires large current but GPIO of ESP32 output capability cannot meet this requirement, a NPN transistor is needed to amplify the current.
Transistor is a semiconductor that controls current. It amplifies weak signals or works as a non-contact switch.
According to structures, it can be divided into NPN and PNP. Both of them comes with three electrodes: base(B), collector© and emitter(E). The PN junction between E and B is also named “emitting junction”, and that between C and B is also called “collecting junction”.
You can learn more about transistor from Wiki: P-N junction - Wikipedia
As shown below, the arrow points to the direction of current flow.
When there is current passing between “BE”, “CE” will allow several-folded current pass (amplified by the transistor). At this point, transistor works in the amplifying area. When current between “BE” exceeds a certain value, “CE” will not allow current to increase any longer. Now the transistor works in the saturation area.
Here are the two types of transistor: PNP and NPN
In this kit, we mark PNP transistor as 8550, and NPN as 8050.
It is often used as a switch in digital circuits. As microcontroller’s capacity to output current is very weak, transistor is a perfect choice to amplify current and drive large-current components.
NPN transistor drives buzzer: If GPIO outputs high, current will flow through R1, the transistor will get conducted, and the buzzer will emit sound. If GPIO outputs low, no current flows through R1, so the transistor will not be conducted to enable buzzer to sound.
PNP transistor drives buzzer: If GPIO outputs low, current will flow through R1, the transistor will get conducted, and the buzzer will emit sound. If GPIO outputs high, no current flows through R1, so the transistor will not be conducted to enable buzzer to sound.
3. Components
ESP32 main board x1 |
NPN transistor (S8050) x1 |
active buzzer x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
mobile device x1 |
1kΩ resistor x1 |
10kΩ resistor x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Download and install the LightBlue APP:
⚠️Note: if you have downloaded and installed the LightBlue APP in the previous lesson 1-2-01, you can skip this step; Otherwise, follow the instructions in lesson 1-2-01 to download and install the LightBlue APP
6. Test Code
/*
* Filename: IoT_Bluetooth Control buzzer
* Function: Bluetooth + APP controls the active buzzer to sound
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEUtils.h"
#include "BLE2902.h"
const int buzzerPin = 13; // Define Active buzzer pin to IO13.
// Define the Bluetooth device name
const char *bleName = "ESP32_Bluetooth";
// Define the received text and the time of the last message
String receivedText = "";
unsigned long lastMessageTime = 0;
// Define the UUIDs of the service and characteristics
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Define the Bluetooth characteristic
BLECharacteristic *pCharacteristic;
void setup() {
Serial.begin(115200); // Initialize the serial port
setupBLE(); // Initialize the Bluetooth BLE
pinMode(buzzerPin, OUTPUT); // Set Active buzzer pin to output
}
void loop() {
// When the received text is not empty and the time since the last message is over 1 second
// Send a notification and print the received text
if (receivedText.length() > 0 && millis() - lastMessageTime > 1000) {
Serial.print("Received message: ");
Serial.println(receivedText);
pCharacteristic->setValue(receivedText.c_str());
pCharacteristic->notify();
receivedText = "";
}
// Read data from the serial port and send it to BLE characteristic
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
const char *newValue = str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
// Define the BLE server callbacks
class MyServerCallbacks : public BLEServerCallbacks {
// Print the connection message when a client is connected
void onConnect(BLEServer *pServer) {
Serial.println("Connected");
}
// Print the disconnection message when a client is disconnected
void onDisconnect(BLEServer *pServer) {
Serial.println("Disconnected");
}
};
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = std::string(pCharacteristic->getValue().c_str());
if (value == "buzzer_on") {
digitalWrite(buzzerPin, HIGH); // turn on active buzzer .
Serial.println("buzzer turned on");
} else if (value == "buzzer_off") {
digitalWrite(buzzerPin, LOW); // turn off active buzzer .
Serial.println("buzzer turned off");
}
}
};
// Initialize the Bluetooth BLE
void setupBLE() {
BLEDevice::init(bleName); // Initialize the BLE device
BLEServer *pServer = BLEDevice::createServer(); // Create the BLE server
// Print the error message if the BLE server creation fails
if (pServer == nullptr) {
Serial.println("Error creating BLE server");
return;
}
pServer->setCallbacks(new MyServerCallbacks()); // Set the BLE server callbacks
// Create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Print the error message if the BLE service creation fails
if (pService == nullptr) {
Serial.println("Error creating BLE service");
return;
}
// Create the BLE characteristic for sending notifications
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902()); // Add the descriptor
// Create the BLE characteristic for receiving data
BLECharacteristic *pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks()); // Set the BLE characteristic callbacks
pService->start(); // Start the BLE service
pServer->getAdvertising()->start(); // Start advertising
Serial.println("Waiting for a client connection..."); // Wait for a client connection
}
7. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-03 IoT Bluetooth Control Buzzer , open file IoT_Bluetooth_Control_Buzzer.ino , or copy and paste the above test code into the Arduino IDE.
2. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
3. After uploading code, enable Bluetooth on your mobile device (smartphone) and open LightBlue.
4. In Peripherals, find ESP32-Bluetooth and click “Connect”. If you don’t see it, try refreshing the page a few times. Once “Connected”, the Bluetooth is connected. Scroll down to set 3 UUIDs in the code. And Arduino IDE serial monitor shows “Connected”.
(⚠️ATTENTION: On iOS devices, if the LightBlue APP you downloaded and installed is an older version, find MPY ESP32 and click “Connect”. If LightBlue is a new version, find ESP32-Bluetooth and click “Connect”. Other operations are similar to Android system.)
5. Tap Send UUID and “HEX” to enter Format Selection , choose “UTF-8 String” to “Save”.
6. Click “Write New Value” to edit commands. Now try to send the command: “buzzer_on” to check whether the active buzzer responses to this command. Input “buzzer_on” and click “Write” to hear whether the active buzzer beeps. At the same time, the serial monitor prints the corresponding messages.
7. Click “Write New Value” to edit commands. Now try to send the command: “buzzer_off” to check whether the active buzzer responses to this command. Input “buzzer_off” and click “Write” to hear whether the active buzzer stays quiet. At the same time, the serial monitor prints the corresponding messages.
8. Code Explanation
Please refer the 1-2-02 to see detailed code explanations.
1-2-04 IoT Bluetooth Control Relay
1. Overview
In daily life, we generally use 220V AC to drive electrical appliances and control them with switches. However, if the switch is directly connected to the 220V AC circuit, once leakage occurs and people will be in danger.
Therefore, in this project, we specially designed this relay module with NO(normally open) and NC(normally closed) to work with wireless data transmission of Bluetooth.
2. Components
ESP32 main board x1 |
breadboard x1 |
mobile device x1 |
relay x1 |
LED x1 |
220Ω resistor x1 |
jumper wires |
Micro USB cable x1 |
M-F DuPont wires |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Download and install the LightBlue APP:
⚠️Note: if you have downloaded and installed the LightBlue APP in the previous lesson 1-2-01, you can skip this step; Otherwise, follow the instructions in lesson 1-2-01 to download and install the LightBlue APP
5. Test Code
/*
* Filename: IoT_Bluetooth_Control_Relay
* Function: Bluetooth + APP controls relay to connect and disconnect
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEUtils.h"
#include "BLE2902.h"
const int relayPin = 12; // Define relay pin to IO12.
// Define the Bluetooth device name
const char *bleName = "ESP32_Bluetooth";
// Define the received text and the time of the last message
String receivedText = "";
unsigned long lastMessageTime = 0;
// Define the UUIDs of the service and characteristics
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Define the Bluetooth characteristic
BLECharacteristic *pCharacteristic;
void setup() {
Serial.begin(115200); // Initialize the serial port
setupBLE(); // Initialize the Bluetooth BLE
pinMode(relayPin, OUTPUT); // Set Active buzzer pin to output
}
void loop() {
// When the received text is not empty and the time since the last message is over 1 second
// Send a notification and print the received text
if (receivedText.length() > 0 && millis() - lastMessageTime > 1000) {
Serial.print("Received message: ");
Serial.println(receivedText);
pCharacteristic->setValue(receivedText.c_str());
pCharacteristic->notify();
receivedText = "";
}
// Read data from the serial port and send it to BLE characteristic
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
const char *newValue = str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
// Define the BLE server callbacks
class MyServerCallbacks : public BLEServerCallbacks {
// Print the connection message when a client is connected
void onConnect(BLEServer *pServer) {
Serial.println("Connected");
}
// Print the disconnection message when a client is disconnected
void onDisconnect(BLEServer *pServer) {
Serial.println("Disconnected");
}
};
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = std::string(pCharacteristic->getValue().c_str());
if (value == "relay_on") {
digitalWrite(relayPin, HIGH); // turn on relay .
Serial.println("relay on");
} else if (value == "relay_off") {
digitalWrite(relayPin, LOW); // relay off.
Serial.println("relay off");
}
}
};
// Initialize the Bluetooth BLE
void setupBLE() {
BLEDevice::init(bleName); // Initialize the BLE device
BLEServer *pServer = BLEDevice::createServer(); // Create the BLE server
// Print the error message if the BLE server creation fails
if (pServer == nullptr) {
Serial.println("Error creating BLE server");
return;
}
pServer->setCallbacks(new MyServerCallbacks()); // Set the BLE server callbacks
// Create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Print the error message if the BLE service creation fails
if (pService == nullptr) {
Serial.println("Error creating BLE service");
return;
}
// Create the BLE characteristic for sending notifications
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902()); // Add the descriptor
// Create the BLE characteristic for receiving data
BLECharacteristic *pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks()); // Set the BLE characteristic callbacks
pService->start(); // Start the BLE service
pServer->getAdvertising()->start(); // Start advertising
Serial.println("Waiting for a client connection..."); // Wait for a client connection
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-04 IoT Bluetooth Control Relay , open file IoT_Bluetooth_Control_Relay.ino , or copy and paste the above test code into the Arduino IDE.
2. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
3. After uploading code, enable Bluetooth on your mobile device (smartphone) and open LightBlue.
4. In Peripherals, find ESP32-Bluetooth and click “Connect”. If you don’t see it, try refreshing the page a few times. Once “Connected”, the Bluetooth is connected. Scroll down to set 3 UUIDs in the code. And Arduino IDE serial monitor shows “Connected”.
(⚠️ATTENTION: On iOS devices, if the LightBlue APP you downloaded and installed is an older version, find MPY ESP32 and click “Connect”. If LightBlue is a new version, find ESP32-Bluetooth and click “Connect”. Operations are similar to Android system.)
5. Tap Send UUID and “HEX” to enter Format Selection , choose “UTF-8 String” to “Save”.
6. Click “Write New Value” to edit commands. Now try to send the command: “relay_on” to check whether the relay responses to this command. Input “relay_on” and click “Write” to see whether the LED controlled by the relay lights up. At the same time, the serial monitor prints the corresponding messages.
7. Click “Write New Value” to edit commands. Now try to send the command: “relay_off” to check whether the relay responses to this command. Input “relay_off” and click “Write” to see whether the LED controlled by the relay turns off. At the same time, the serial monitor prints the corresponding messages.
7. Code Explanation
Please refer the 1-2-02 to see detailed code explanations.
1-2-05 IoT Bluetooth Control RGB LED
1. Overview
In previous experiments, we have learned how Bluetooth transmits data and controls sensors. Here we configure RGB LED to set custom commands such as “led_off”, “red” and “green”. These commands allow you to control the on and off of the RGB LED by sending commands from LightBlue APP on your mobile device.
2. Components
ESP32 main board x1 |
RGB LED x1 |
220Ω resistor x3 |
mobile device x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
3. Wiring Diagram
There are 4 pins: the longest is GND; The others are red, green and blue. Place the RGB led as shown, the second from the left being the longest pin. So the pin numbers should be red, GND, green and blue.
Schematic diagram:
Wiring diagram:
4. Download and install the LightBlue APP:
⚠️Note: if you have downloaded and installed the LightBlue APP in the previous lesson 1-2-01, you can skip this step; Otherwise, follow the instructions in lesson 1-2-01 to download and install the LightBlue APP
5. Test Code
Here, we can choose our favorite color in the drawing software and display it with RGB LED.
/*
* Filename: IoT_Bluetooth Control RGB LED
* Function: Bluetooth control RGB
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include "BLEDevice.h"
#include "BLEServer.h"
#include "BLEUtils.h"
#include "BLE2902.h"
// Define RGB LED pins
const int ledPins[] = {27, 25, 26}; // Define the red, green, and blue pins in turn
const byte chns[] = {0, 1, 2}; // Define the PWM channel
int red, green, blue;
// Define the Bluetooth device name
const char *bleName = "ESP32_Bluetooth";
// Define the received text and the time of the last message
String receivedText = "";
unsigned long lastMessageTime = 0;
// Define the UUIDs of the service and characteristics
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Define the Bluetooth characteristic
BLECharacteristic *pCharacteristic;
void setup() {
Serial.begin(115200); // Initialize the serial port
setupBLE(); // Initialize the Bluetooth BLE
// Set pwm channel,1KHz,8bit
for (int i = 0; i < 3; i++) {
ledcSetup(chns[i], 1000, 8);
ledcAttachPin(ledPins[i], chns[i]);
}
}
void loop() {
// When the received text is not empty and the time since the last message is over 1 second
// Send a notification and print the received text
if (receivedText.length() > 0 && millis() - lastMessageTime > 1000) {
Serial.print("Received message: ");
Serial.println(receivedText);
pCharacteristic->setValue(receivedText.c_str());
pCharacteristic->notify();
receivedText = "";
}
// Read data from the serial port and send it to BLE characteristic
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
const char *newValue = str.c_str();
pCharacteristic->setValue(newValue);
pCharacteristic->notify();
}
}
// Define the BLE server callbacks
class MyServerCallbacks : public BLEServerCallbacks {
// Print the connection message when a client is connected
void onConnect(BLEServer *pServer) {
Serial.println("Connected");
}
// Print the disconnection message when a client is disconnected
void onDisconnect(BLEServer *pServer) {
Serial.println("Disconnected");
}
};
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = std::string(pCharacteristic->getValue().c_str());
if (value == "led_off") {
setColor(0, 0, 0); // turn the RGB LED off
Serial.println("RGB LED turned off");
} else if (value == "red") {
setColor(255, 0, 0); // Red
Serial.println("red");
}
else if (value == "green") {
setColor(0, 255, 0); // green
Serial.println("green");
}
else if (value == "blue") {
setColor(0, 0, 255); // blue
Serial.println("blue");
}
else if (value == "yellow") {
setColor(255, 150, 0); // yellow
Serial.println("yellow");
}
else if (value == "purple") {
setColor(80, 0, 80); // purple
Serial.println("purple");
}
}
};
// Initialize the Bluetooth BLE
void setupBLE() {
BLEDevice::init(bleName); // Initialize the BLE device
BLEServer *pServer = BLEDevice::createServer(); // Create the BLE server
// Print the error message if the BLE server creation fails
if (pServer == nullptr) {
Serial.println("Error creating BLE server");
return;
}
pServer->setCallbacks(new MyServerCallbacks()); // Set the BLE server callbacks
// Create the BLE service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Print the error message if the BLE service creation fails
if (pService == nullptr) {
Serial.println("Error creating BLE service");
return;
}
// Create the BLE characteristic for sending notifications
pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
pCharacteristic->addDescriptor(new BLE2902()); // Add the descriptor
// Create the BLE characteristic for receiving data
BLECharacteristic *pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pCharacteristicRX->setCallbacks(new MyCharacteristicCallbacks()); // Set the BLE characteristic callbacks
pService->start(); // Start the BLE service
pServer->getAdvertising()->start(); // Start advertising
Serial.println("Waiting for a client connection..."); // Wait for a client connection
}
void setColor(int red, int green, int blue) {
// For common-cathode RGB LEDs, use 255 minus the color value
ledcWrite(chns[0], red);
ledcWrite(chns[1], green);
ledcWrite(chns[2], blue);
}
Write the RGB value to setColor() and you will be able to see RGB light up the color you want.
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-05 IoT Bluetooth Control RGB LED , open file IoT_Bluetooth_Control_RGB_LED.ino , or copy and paste the above test code into the Arduino IDE.
2. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
3. After uploading code, enable Bluetooth on your mobile device (smartphone) and open LightBlue.
4. In Peripherals, find ESP32-Bluetooth and click “Connect”. If you don’t see it, try refreshing the page a few times. Once “Connected”, the Bluetooth is connected. Scroll down to set 3 UUIDs in the code. And Arduino IDE serial monitor shows “Connected”.
(⚠️ATTENTION: On iOS devices, if the LightBlue APP you downloaded and installed is an older version, find MPY ESP32 and click “Connect”. If LightBlue is a new version, find ESP32-Bluetooth and click “Connect”. Operations are similar to Android system.)
5. Tap Send UUID and “HEX” to enter Format Selection , choose “UTF-8 String” to “Save”.
6. Click “Write New Value” to edit commands. Now try to send the commands: “red”, “green”, “blue”, “yellow”, “purple”, “led_off” to check whether the RGB LED responses to these commands. Input “red” and click “Write” to see whether the LED lights up in red. At the same time, the serial monitor prints the corresponding messages. So do the others.
7. Code Explanation
This project includes RGB LED configuration and custom commands such as “led_off”, “red” and “green”. These commands allow you to control the on and off of the RGB LED by sending commands from LightBlue APP on your mobile device.
Let’s explain the code in details:
Add new global variables for RGB LED pins and PWM channels.
// Define RGB LED pins
const int ledPins[] = {27, 25, 26}; // Define the red, green, and blue pins in turn
const byte chns[] = {0, 1, 2}; // Define PWM channel
int red, green, blue;
setup()
initializes the PWM channel with a predefined frequency and resolution, and then connects the RGB LED pins to their respective PWM channels.
// Set pwm channel, 1KHz, 8bit
for (int i = 0; i < 3; i++) {
ledcSetup(chns[i], 1000, 8);
ledcAttachPin(ledPins[i], chns[i]);
}
Modify onWrite method in class
MyCharacteristicCallbacks
. This function listens for data coming from the Bluetooth connection and controls RGB LED according to the received string (such as “led_off”, “red”, “green”, etc.)
// Define the BLE characteristic callbacks
class MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = std::string(pCharacteristic->getValue().c_str());
if (value == "led_off") {
setColor(0, 0, 0); // turn the RGB LED off
Serial.println("RGB LED turned off");
} else if (value == "red") {
setColor(255, 0, 0); // Red
Serial.println("red");
}
else if (value == "green") {
setColor(0, 255, 0); // green
Serial.println("green");
}
else if (value == "blue") {
setColor(0, 0, 255); // blue
Serial.println("blue");
}
else if (value == "yellow") {
setColor(255, 150, 0); // yellow
Serial.println("yellow");
}
else if (value == "purple") {
setColor(80, 0, 80); // purple
Serial.println("purple");
}
}
};
Finally, the ability to set RGB LED colors has been added.
void setColor(int red, int green, int blue) {
// For common-cathode RGB LEDs, use 255 minus the color value
ledcWrite(chns[0], red);
ledcWrite(chns[1], green);
ledcWrite(chns[2], blue);
}
In summary, this script enables a remote control interaction where the ESP32 runs as a Bluetooth Low Power (BLE) server. A connected BLE client (such as a smartphone) can send a string command to change the color of the RGB LED. Also, the ESP32 provides feedback to the client by sending the received string so that the client knows what action has been performed.
1-2-06 IoT Bluetooth Audio Player
1. Overview
Here we provide a simple solution to play audio from Bluetooth devices by the ESP32 DAC.
The project involves ESP32-A2DP library that is used to receive audio data from Bluetooth devices. These data is then transmitted to the ESP32 internal DAC via the I2S interface. The I2S interface is configured in master mode, transfer mode, and built-in DAC mode. Then the audio data is played by the passive buzzer connected to the DAC.
When using the ESP32’s internal DAC, it is important to ensure that the audio data is in the correct format and sampling rate to prevent distortion or noise during playback.
2. Components
ESP32 main board x1 |
NPN transistor (S8050) x1 |
passive buzzer x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
mobile device x1 |
1kΩ resistor x1 |
10kΩ resistor x1 |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Test Code
/*
* Filename: IoT Bluetooth Audio Player
* Function: Bluetooth controls the passive buzzer to play music
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
// ==> Example to use built in DAC of ESP32
#include "BluetoothA2DPSink.h"
BluetoothA2DPSink a2dp_sink;
int LEDC_CHANNEL_0 = 0; // The LEDC timer uses channel 0
int LEDC_TIMER_13_BIT = 8; // LEDC timer uses 8-bit precision
const int BUZZER_PIN = 25; // Define tool I/O ports
// Create a music melody list
int melody[] = {330,330,330,262,330,392,196,262,196,165,220,247,233,220,196,330,392,440,349,392,330,262,294,247,262,196,165,220,247,233,220,196,330,392,440,349,392,330,262,294,247,392,370,330,311,330,208,220,262,220,262,294,392,370,330,311,330,523,523,523,392,370,330,311,330,208,220,262,220,262,294,311,294,262,262,262,262,262,294,330,262,220,196,262,262,262,262,294,330,262,262,262,262,294,330,262,220,196};
// Create a list of tone durations
int noteDurations[] = {8,4,4,8,4,2,2,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,3,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,2,8,8,8,4,4,8,8,4,8,8,3,8,8,8,4,4,4,8,2,8,8,8,4,4,8,8,4,8,8,3,3,3,1,8,4,4,8,4,8,4,8,2,8,4,4,8,4,1,8,4,4,8,4,8,4,8,2};
void setup() {
const i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = 44100, // corrected by info from bluetooth
.bits_per_sample = (i2s_bits_per_sample_t)16, //the DAC module will only take the 8bits from MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
a2dp_sink.set_i2s_config(i2s_config);
a2dp_sink.start("ESP32_Bluetooth");
pinMode(BUZZER_PIN, OUTPUT); // Set the buzzer to output mode
int noteDuration; // Create a variable noteDuration
for (int i = 0; i < sizeof(noteDurations); ++i){
noteDuration = 800/noteDurations[i];
ledcSetup(LEDC_CHANNEL_0, melody[i]*2, LEDC_TIMER_13_BIT);
ledcAttachPin(BUZZER_PIN, LEDC_CHANNEL_0);
ledcWrite(LEDC_CHANNEL_0, 50);
delay(noteDuration * 1.30); // delay
}
}
void loop() {
}
5. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-06 IoT Bluetooth Audio Player , open file IoT_Bluetooth_Audio_Player.ino , or copy and paste the above test code into the Arduino IDE.
2. Check whether the required library ESP32-A2DP is installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
⚠️ATTENTION: If you are using ESP32 development board version 3.0.0 or later, you may encounter errors during compilation. Because later versions of the board no longer support ESP32-A2DP library. For this example to work properly, it is recommended to use the firmware version 1.06 (This tutorial is all in version 1.06).
3. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
4. After uploading the code, open the Bluetooth for scaning, and connect to ESP32_Bluetooth.
5. The passive buzzer connected to the ESP32 plays the audio.
6. Code Explanation
1. Include BluetoothA2DPSink.h
library. This library is used to receive audio data from Bluetooth-enabled devices. The I2S interface Settings then create and configure BluetoothA2DPSink
instance.
#include "BluetoothA2DPSink.h"
BluetoothA2DPSink a2dp_sink;
2. setup()
initializes the structure of i2s_config_t with the configuration required for the I2S (Inter-IC Sound) interface.
const i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
.sample_rate = 44100, // corrected by info from bluetooth
.bits_per_sample = (i2s_bits_per_sample_t)16, //the DAC module will only take the 8bits from MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
The I2S interface transfers digital audio data between devices.
Configuration includes
I2S mode
,sample rate
,bits per sample
,channel format
,communication format
,interrupt allocation flags
,DMA buffer count
,DMA buffer length
, and whether to use APLL(Audio PLL).Pass the
i2s_config_t struct
structure as a parameter to the functionset_i2s_config
of the objectBluetoothA2DPSink
, so that to configure the I2S interface for audio playback.Call
BluetoothA2DPSink
objectstart
function to activate the Bluetooth audio receiver and start playing audio through the built-in DAC.
1-2-07 ESP32 Web Server of WiFi Station Mode
1. Overview
One of the most useful features of the ESP32 is that it can not only act as a Web server, but also to create its own network for other devices to connect to and access web pages. ESP32 can run in three modes: Station (STA) mode, Soft Access Point (AP) mode, and Station+AP mode.
Station mode: Actively connect to the router as a WiFi device, also known as WiFi Client
AP mode: As an Access Point for other WiFi devices to connect to, i.e., WiFi hotspots
Station+AP mode: While the ESP32 connects to the router, it is also a hotspot for other WiFi devices to connect to.
All WiFi programming projects must be configured with WiFi running mode before using, otherwise the WiFi cannot be used. In this project, we are going to learn the ESP32 WiFi Station Mode.
2. Component Knowledge
Station Mode
In Station mode, the ESP32 connects to an existing WiFi network (a network created by a wireless router).
When setting Station mode, the ESP32 is taken as a WiFi client. It can connect to the router network and communicate with other devices on the router via a WiFi connection. As shown in the figure below, the PC and the mobile device have been connected to the router. If the ESP32 wants to communicate with the PC and the mobile device, they need to be connected to the router.
In Station mode, the ESP32 gets its IP address from the wireless router it is connected to. With this IP address, it can set up a Web server and serve web pages to all connected devices on an existing WiFi network.
3. Components
ESP32 main board x1 |
red LED x1 |
breadboard x1 |
jumper wires |
yellow LED x1 |
220Ω resistor x2 |
mobile device x1 |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: ESP32 Web server of WiFi Station Mode
* Function: Configure the ESP32 Web server in WiFi Station(STA) mode
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <WiFi.h>
#include <WebServer.h>
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
WebServer server(80);
uint8_t LED1pin = 17;
bool LED1status = LOW;
uint8_t LED2pin = 13;
bool LED2status = LOW;
void setup() {
Serial.begin(115200);
delay(100);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, HIGH);}
else
{digitalWrite(LED1pin, LOW);}
if(LED2status)
{digitalWrite(LED2pin, HIGH);}
else
{digitalWrite(LED2pin, LOW);}
}
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
Serial.println("GPIO17 Status: OFF | GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status));
}
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO17 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO17 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO13 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(uint8_t led1stat,uint8_t led2stat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<h1>ESP32 Web Server</h1>\n";
ptr +="<h3>Using Station(STA) Mode</h3>\n";
if(led1stat)
{ptr +="<p>LED1 Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>LED1 Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>LED2 Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>LED2 Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-07 ESP32 Web Server of WiFi Station Mode , open file Web_Server_of_WiFi_Station_Mode.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
4. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
5. Open the browser of your smartphone and enter the WIFI IP address (192.168.0.69) in the serial monitor, and then click “search”.
6. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page shows the current status of leds and two buttons for controlling them. At the same time, you can view the serial monitor to see the status of the GPIO pins of the ESP32.
7. Click “ON” to turn on LED1. Once the button is clicked, the ESP32 receives the request to /led1on URL. It then turns on the LED1 and provides a web page with an updated LED status. It also prints the GPIO pin status on the serial monitor.
8. You can press the LED2 button to see if it works similarly.
7. Code Explanation
Let’s explain the code in details:
Include
WiFi.h
library. The library contains the specific methods we used to connect the ESP32 to the network; TheWebServer.h
also contains methods that will help us configure the server and process incoming HTTP requests.
#include <WiFi.h>
#include <WebServer.h>
Since we configured the ESP32 Web server in Station mode, it will create its own WiFi network. Therefore, we need to set our SSID and Password.
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
Create
WebServer
library instance to access its functions that accepts the port on which the server will listen as a parameter. Since HTTP uses port 80 by default, this value will be adopted. This allows us to connect to the server without specifying a port in the URL.
// declare an object of WebServer library
WebServer server(80);
Declare the GPIO pins of the ESP32 to which the leds are connected, and their initial states.
uint8_t LED1pin = 17;
bool LED1status = LOW;
uint8_t LED2pin = 13;
bool LED2status = LOW;
setup()
configures the ESP32 Web server to Station mode. We first set up a serial baud rate for debugging serial connections and configure the GPIO pin to OUTPUT.
Serial.begin(115200);
delay(100);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);
WiFi.begin()
makes it join an existing network.
//connect to your local wi-fi network
WiFi.begin(ssid, password);
When the ESP32 tries to connect to the network, we use
WiFi.status()
to check the connection status.
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Once connected to the network,
WiFi.localIP()
prints the IP address of the ESP32.
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
In order to handle incoming HTTP requests, we must specify what code should be executed when accessing a particular URL. Therefore,
.on()
is used. It takes two parameters: a relative URL path and the name of the function to execute when accessing that URL.For example, the first line of the following code indicates that the server will call the function
handle_OnConnect()
when it receives an HTTP request on the root (/) path. However, note that the specified URL is a relative path.Similarly, we must specify four more URLs to handle the two states of the two leds.
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
If the URL requested by the client is not specified by
server.on()
, and we haven’t specified what service the server should provide, it should response a 404 error (Page Not Found). Therefore,server.onNotFound()
is adopted.
server.onNotFound(handle_NotFound);
begin() of the server object starts the server.
server.begin();
Serial.println("HTTP server started");
The actual incoming HTTP request is processed in
loop()
. Therefore, we usehandleClient()
. We also change the state of the led upon request.
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, HIGH);}
else
{digitalWrite(LED1pin, LOW);}
if(LED2status)
{digitalWrite(LED2pin, HIGH);}
else
{digitalWrite(LED2pin, LOW);}
}
handle_OnConnect()
must be written. Theserver.on
appended it to the root (/) URL before. We set the status of both leds to LOW (the initial states) and print them on the serial monitor to enable this function.“send” responds to the HTTP request. Although this method can be invoked with many different parameters, it is easiest to use the HTTP response code, content type, and content. The first parameter passed to “send” is the code 200 (one of the HTTP status codes), which corresponds to the OK response. Then we set the content type to “text/html” and pass custom function
SendHTML()
to generate dynamic html pages with LED status.
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
Serial.println("GPIO17 Status: OFF | GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status));
}
Five functions were written to handle LED on/off requests and 404 error pages.
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO17 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO17 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO13 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
Display HTML web pages. When the ESP32 Web server receives a request from a Web client,
SendHTML()
generates a Web page. It simply concatenates the HTML code into a long string and returns it toserver.send()
. This function uses the state of the led as a parameter to dynamically generate HTML content. The first text you should send is always <!DOCTYPE> declaration, meaning that HTML code is being sent.
String SendHTML(uint8_t led1stat,uint8_t led2stat){
String ptr = "<!DOCTYPE html> <html>\n";
viewport element makes the web page responsive, ensuring that it looks good on all devices. The title tag determines the title of the page.
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
Design the web page style. We use CSS to design the buttons and the overall look of the page. We selected the Helvetica font and defined the content displayed as inline blocks, centered.
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
Set the colors around the body, H1, H3, and p tags, set the fonts and margins.
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
These buttons can also be styled by colosr, sizes, margins and so on. :active selector changes the appearance of the button when it is pressed.
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
Set the title of the page. You can change this text to anything that suits your application.
ptr +="<h1>ESP32 Web Server</h1>\n";
ptr +="<h3>Using Station(STA) Mode</h3>\n";
Display buttons and their status. The if statement is used to dynamically update the status of buttons and leds.
if(led1stat)
{ptr +="<p>LED1 Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>LED1 Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>LED2 Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>LED2 Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
1-2-08 ESP32 Web Server of WiFi Soft AP
1. Overview
We have learned that ESP32 can run in three modes:
Station mode: Actively connect to the router as a WiFi device, also known as WiFi Client
AP mode: As an Access Point for other WiFi devices to connect to, i.e., WiFi hotspots
Station+AP mode: While the ESP32 connects to the router, it is also a hotspot for other WiFi devices to connect to.
All WiFi programming projects must be configured with WiFi running mode before using, otherwise the WiFi cannot be used. In this project, we are going to learn the ESP32 WiFi AP Mode.
2. Component Knowledge
AP Mode
In Access Point(AP) mode, ESP32 can set up its own WiFi network and act as a router, just like a WiFi router. However, unlike a WiFi router, it doesn’t have an interface to connect to a wired network. Therefore, it is called the Access Point(AP) mode and it cannot connect more than 5 sites at the same time.
In AP mode, ESP32 creates a new WiFi network and assigns it an SSID (network name) and an IP address. With this IP address, it can serve web pages to all connected devices.
3. Components
ESP32 main board x1 |
red LED x1 |
breadboard x1 |
jumper wires |
yellow LED x1 |
220Ω resistor x2 |
mobile device x1 |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
⚠️ATTENTION: The WiFi name, passwords and IP address do not need to be modified, and can be directly used.
/*
* Filename : ESP32 Web Server of WiFi Soft AP
* Function : Configure the ESP32 Web server in WiFi Soft Access Point(AP) mode
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <WiFi.h>
#include <WebServer.h>
/* Put your SSID & Password */
const char* ssid = "ESP32"; //Enter SSID here
const char* password = "12345678"; //Enter Password here
/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
WebServer server(80);
uint8_t LED1pin = 17;
bool LED1status = LOW;
uint8_t LED2pin = 13;
bool LED2status = LOW;
void setup() {
Serial.begin(115200);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);
WiFi.softAP(ssid, password);
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100);
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, HIGH);}
else
{digitalWrite(LED1pin, LOW);}
if(LED2status)
{digitalWrite(LED2pin, HIGH);}
else
{digitalWrite(LED2pin, LOW);}
}
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
Serial.println("GPIO17 Status: OFF | GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status));
}
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO17 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO17 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO13 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(uint8_t led1stat,uint8_t led2stat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<h1>ESP32 Web Server</h1>\n";
ptr +="<h3>Using Access Point(AP) Mode</h3>\n";
if(led1stat)
{ptr +="<p>LED1 Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>LED1 Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>LED2 Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>LED2 Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-08 ESP32 Web Server of WiFi Soft AP , open file ESP32_Web_Server_of_WiFi_Soft_AP.ino , or copy and paste the above test code into the Arduino IDE.
2. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
3. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding messages will be displayed on the monitor.
⚠️Note that if there is nothing on the monitor, please press the RESET button on the ESP32 board.
4. Now, connect your phone, laptop or other device to a WiFi network called “ESP32”. The password is 12345678.
5. Once connected to the ESP32 AP network, open your browser and access 192.168.1.1. The ESP32 should return a web page showing the current status of the leds and buttons. At the same time, you can check the status of the ESP32 GPIO pins on the serial monitor.
6. Click “ON” to turn on LED1. Once the button is clicked, the ESP32 receives the request to /led1on
URL. It then turns on the LED1 and provides a web page with an updated LED status. It also prints the GPIO pin status on the serial monitor.
7. You can press the LED2 button to see if it works similarly.
7. Code Explanation
Let’s explain the code in details:
Include
WiFi.h
library. The library contains the specific methods we used to connect the ESP32 to the network; TheWebServer.h
also contains methods that will help us configure the server and process incoming HTTP requests.
#include <WiFi.h>
#include <WebServer.h>
Since we configured the ESP32 Web server in Access Point(AP) mode, it will create its own WiFi network. Therefore, we need to set our SSID, passwords, IP address, IP subnet mask and IP gateway.
/* Put your SSID & Password */
const char* ssid = "ESP32"; // Enter SSID here
const char* password = "12345678"; //Enter Password here
/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);
Create
WebServer
library instance to access its functions that accepts the port on which the server will listen as a parameter. Since HTTP uses port 80 by default, this value will be adopted. This allows us to connect to the server without specifying a port in the URL.
WebServer server(80);
Declare the GPIO pins of the ESP32 to which the leds are connected, and their initial states.
uint8_t LED1pin = 17;
bool LED1status = LOW;
uint8_t LED2pin = 13;
bool LED2status = LOW;
setup()
configures the ESP32 Web server to Access Point(AP) mode. We first set up a serial baud rate for debugging serial connections and configure the GPIO pin to OUTPUT.
Serial.begin(115200);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);
We provide SSID, password, IP address, IP subnet mask, and IP gateway to configure the soft access point to create the Wi-Fi network.
WiFi.softAP(ssid, password);
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100);
When the ESP32 tries to connect to the network, we can use WiFi.status() to check the connection status.
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
In order to handle incoming HTTP requests, we must specify what code should be executed when accessing a particular URL. Therefore,
.on()
is used. It takes two parameters: a relative URL path and the name of the function to execute when accessing that URL.For example, the first line of the following code indicates that the server will call the function
handle_OnConnect()
when it receives an HTTP request on the root (/) path. However, note that the specified URL is a relative path.Similarly, we must specify four more URLs to handle the two states of the two leds.
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
If the URL requested by the client is not specified by
server.on()
, and we haven’t specified what service the server should provide, it should response a 404 error (Page Not Found). Therefore,server.onNotFound()
is adopted.
server.onNotFound(handle_NotFound);
begin()
of the server object starts the server.
server.begin();
Serial.println("HTTP server started");
The actual incoming HTTP request is processed in
loop()
. Therefore, we usehandleClient()
. We also change the state of the led upon request.
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, HIGH);}
else
{digitalWrite(LED1pin, LOW);}
if(LED2status)
{digitalWrite(LED2pin, HIGH);}
else
{digitalWrite(LED2pin, LOW);}
}
handle_OnConnect()
must be written. Theserver.on
appended it to the root (/) URL before. We set the status of both leds to LOW (the initial states) and print them on the serial monitor to enable this function.“send” responds to the HTTP request. Although this method can be invoked with many different parameters, it is easiest to use the HTTP response code, content type, and content. The first parameter passed to “send” is the code 200 (one of the
HTTP status codes
), which corresponds to the OK response. Then we set the content type to “text/html” and pass custom functionSendHTML()
to generate dynamic html pages with LED status.
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
Serial.println("GPIO17 Status: OFF | GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status));
}
Five functions were written to handle LED on/off requests and 404 error pages.
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO17 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO17 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO13 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
Display HTML web pages. When the ESP32 Web server receives a request from a Web client,
SendHTML()
generates a Web page. It simply concatenates the HTML code into a long string and returns it toserver.send()
. This function uses the state of the led as a parameter to dynamically generate HTML content. The first text you should send is always <!DOCTYPE> declaration, meaning that HTML code is being sent.
String SendHTML(uint8_t led1stat,uint8_t led2stat){
String ptr = "<!DOCTYPE html> <html>\n";
viewport element makes the web page responsive, ensuring that it looks good on all devices. The title tag determines the title of the page.
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
Design the web page style. We use CSS to design the buttons and the overall look of the page. We selected the Helvetica font and defined the content displayed as inline blocks, centered.
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
Set the colors around the body, H1, H3, and p tags, set the fonts and margins.
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
These buttons can also be styled by colosr, sizes, margins and so on. :active selector changes the appearance of the button when it is pressed.
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
Set the title of the page. You can change this text to anything that suits your application.
ptr +="<h1>ESP32 Web Server</h1>\n";
ptr +="<h3>Using Access Point(AP) Mode</h3>\n";
Display buttons and their status. The if statement is used to dynamically update the status of buttons and leds.
if(led1stat)
{ptr +="<p>LED1 Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>LED1 Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>LED2 Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>LED2 Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
1-2-09 Create ESP32 Web Server with WebSockets
1. Overview
Now let’s build a WebSocket connected to ESP32 server to remotely control LED. We design a web page with a toggle switch to change the state of the LED that is shown on the WiFi web interface in real-time.
The ESP32 will actively listen for incoming WebSocket connections and messages on port 80. When the user toggles the LED switch on the web page, a “toggle” message is sent to the ESP32. After receiving, ESP32 will switch the LED and immediately notify all connected clients(browsers) by sending a “1”(LED on) or a “0”(LED off). Therefore, all active clients will immediately update the status of the LED on their web pages.
2. Component Knowledge
What is WebSocket?
WebSocket is a communication protocol that supports two-way communication between a client and a Web server. To put it simply, it allows a client and server to establish a connection which either party can send messages to the other at any time.
This is different from a regular HTTP connection, where the client initiates a request, the server sends a response, and the connection terminates.
In fact, WebSocket is a completely different communication protocol - when a client establishes a connection with a server, both ends are able to send and receive data. In other words, not only the server is listening, so are all connected clients. As a result, the server sends data to a specific client or broadcasts it to all clients without a request. Most importantly, the connection will remain active until the client or server closes it for continuous communication between them.
Although WebSocket is great, it should not be used everywhere. It complicates project, especially on the server. Therefore, unless your project involves data broadcasting (where you want to transmit the same data to multiple clients at the same time), you should not do this; Otherwise, polling is recommended.
3. Components
ESP32 main board x1 |
red LED x1 |
breadboard x1 |
jumper wires |
220Ω resistor x1 |
mobile device x1 |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Create ESP32 Web Server with WebSockets
* Function: Use WebSockets to create the ESP32 Web server
* Compiling IDE:ARDUINO 2.3.3
* Author:: https://www.keyestudio.com/
*/
// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
bool ledState = 0;
const int ledPin = 26;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>ESP32 WebSocket Server</title>
<style>
html{font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
body{margin-top: 50px;}
h1{color: #444444;margin: 50px auto;}
p{font-size: 19px;color: #888;}
#state{font-weight: bold;color: #444;}
.switch{margin:25px auto;width:80px}
.toggle{display:none}
.toggle+label{display:block;position:relative;cursor:pointer;outline:0;user-select:none;padding:2px;width:80px;height:40px;background-color:#ddd;border-radius:40px}
.toggle+label:before,.toggle+label:after{display:block;position:absolute;top:1px;left:1px;bottom:1px;content:""}
.toggle+label:before{right:1px;background-color:#f1f1f1;border-radius:40px;transition:background .4s}
.toggle+label:after{width:40px;background-color:#fff;border-radius:20px;box-shadow:0 2px 5px rgba(0,0,0,.3);transition:margin .4s}
.toggle:checked+label:before{background-color:#4285f4}
.toggle:checked+label:after{margin-left:42px}
</style>
</head>
<body>
<h1>ESP32 WebSocket Server</h1>
<div class="switch">
<input id="toggle-btn" class="toggle" type="checkbox" %CHECK%>
<label for="toggle-btn"></label>
</div>
<p>LED: <span id="state">%STATE%</span></p>
<script>
window.addEventListener('load', function() {
var websocket = new WebSocket(`ws://${window.location.hostname}/ws`);
websocket.onopen = function(event) {
console.log('Connection established');
}
websocket.onclose = function(event) {
console.log('Connection died');
}
websocket.onerror = function(error) {
console.log('error');
};
websocket.onmessage = function(event) {
if (event.data == "1") {
document.getElementById('state').innerHTML = "ON";
document.getElementById('toggle-btn').checked = true;
}
else {
document.getElementById('state').innerHTML = "OFF";
document.getElementById('toggle-btn').checked = false;
}
};
document.getElementById('toggle-btn').addEventListener('change', function() { websocket.send('toggle'); });
});
</script>
</body>
</html>
)rawliteral";
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
if (strcmp((char*)data, "toggle") == 0) {
ledState = !ledState;
ws.textAll(String(ledState));
}
}
}
void eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
digitalWrite(ledPin, ledState);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
String processor(const String& var){
if(var == "STATE"){
return ledState ? "ON" : "OFF";
}
if(var == "CHECK"){
return ledState ? "checked" : "";
}
return String();
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
Serial.print("Connecting to ");
Serial.println(ssid);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("Connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
ws.onEvent(eventHandler);
server.addHandler(&ws);
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Start server
server.begin();
}
void loop() {
ws.cleanupClients();
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-09 Create ESP32 Web Server with WebSockets , open file Create_Web_Server_with_WebSockets.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. To build a WebSocket server, use ESPAsyncWebServer library. It only works with AsyncTCP library. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. Press the RESET button on the ESP32 and wait for a while. The corresponding IP address will be displayed on the monitor.
6. Open the browser on your phone and input the WIFI IP address in it and “search”. A web page displays the current status of the LED and switches. The serial monitor shows related information and the IP address changes.
7. Toggle the switch to control LED. You will find that not only the LED turns on, but also the LED state is automatically updated in the web browser.
8. You can keep a close eye on the serial monitor to see if the client disconnects from the ESP32.
7. Code Explanation
Let’s explain the code in details:
The code includes the following libraries:
WiFi.h
: esp32 unique WiFi connection.ESPAsyncWebServer.h
: Create an HTTP server that supports WebSocket endpoints.AsyncTCP.h
: The ESPAsyncWebServer library depends on this library.
// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
Specify the network name and password (SSID and password), replacing them with yours.
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
Define two variables in the same global zone: one to track the current GPIO state (ledState) and one to specify the GPIO pin connected to the LED (ledPin).
bool ledState = 0;
const int ledPin = 26;
Initialize the Web server and WebSocket. Create an
AsyncWebServer
instance named “server”. This function can take as an parameter the port on which the HTTP server listens for incoming requests. Here we will use the default HTTP port 80.
AsyncWebServer server(80);
AsyncWebSocket
,ws
sets the WebSocket endpoint whose path must be passed as an parameter to such functions. This path is defined as a string, and in our code it is set to/ws
, so that WebSocket will listen for connections on the pathws://[esp ip]/ws
.
AsyncWebSocket ws("/ws");
Create a Web page and define
index_html
constant. It contains a raw string (which contains HTML code for displaying toggle switches on the web page, CSS and JavaScript for controlling the LED and styling the web page) to establish a WebSocket connection and monitor changes in LED status. The entire code will be executed on the client side.⚠️ATTENTION: The PROGMEM macros are used here to optimize memory, which stores content in ESP32 program memory (flash) instead of SRAM.
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>ESP32 WebSocket Server</title>
<style>
html{font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
body{margin-top: 50px;}
h1{color: #444444;margin: 50px auto;}
p{font-size: 19px;color: #888;}
#state{font-weight: bold;color: #444;}
.switch{margin:25px auto;width:80px}
.toggle{display:none}
.toggle+label{display:block;position:relative;cursor:pointer;outline:0;user-select:none;padding:2px;width:80px;height:40px;background-color:#ddd;border-radius:40px}
.toggle+label:before,.toggle+label:after{display:block;position:absolute;top:1px;left:1px;bottom:1px;content:""}
.toggle+label:before{right:1px;background-color:#f1f1f1;border-radius:40px;transition:background .4s}
.toggle+label:after{width:40px;background-color:#fff;border-radius:20px;box-shadow:0 2px 5px rgba(0,0,0,.3);transition:margin .4s}
.toggle:checked+label:before{background-color:#4285f4}
.toggle:checked+label:after{margin-left:42px}
</style>
</head>
<body>
<h1>ESP32 WebSocket Server</h1>
<div class="switch">
<input id="toggle-btn" class="toggle" type="checkbox" %CHECK%>
<label for="toggle-btn"></label>
</div>
<p>LED: <span id="state">%STATE%</span></p>
<script>
window.addEventListener('load', function() {
var websocket = new WebSocket(`ws://${window.location.hostname}/ws`);
websocket.onopen = function(event) {
console.log('Connection established');
}
websocket.onclose = function(event) {
console.log('Connection died');
}
websocket.onerror = function(error) {
console.log('error');
};
websocket.onmessage = function(event) {
if (event.data == "1") {
document.getElementById('state').innerHTML = "ON";
document.getElementById('toggle-btn').checked = true;
}
else {
document.getElementById('state').innerHTML = "OFF";
document.getElementById('toggle-btn').checked = false;
}
};
document.getElementById('toggle-btn').addEventListener('change', function() { websocket.send('toggle'); });
});
</script>
</body>
</html>
)rawliteral";
setup()
makes the ESP32 attempt to connect to the WiFi network, and prints the connection progress and obtained IP address to the serial monitor.
Serial.print("Connecting to ");
Serial.println(ssid);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("Connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
WebSocket sets up an event listener, which means that whenever a WebSocket(
ws
object)-related event occurs,eventHandler()
will be triggered to handle the event.eventHandler()
contains logic to determine what type of WebSocket event has occurred (such as a new client connection, received data, client disconnection, etc.) and how to respond to that event.
ws.onEvent(eventHandler);
Attach or register WebSocket(
ws
) to a web server(server
). Tellserver
that a WebSocket handler, and any incoming WebSocket connections or requests should be directed to this handler.&ws
is a pointer to a WebSocket object that allowsserver
to know where to send and where to receive WebSocket-related data.
server.addHandler(&ws);
The Web server has been started. Once executed, the server begins listening for incoming client requests on the previously defined path, such as the root path we set.
// Start server
server.begin();
In
loop()
, in the case of synchronous web servers, we normally callserver.handleclient()
to check if there are any client requests to be processed. If there is, the code will process those requests and send the response before returning control to the rest.
void loop() {
ws.cleanupClients();
}
Handle web placeholders. There are two placeholders:
%CHECK%
and%STATE%
.processor()
is responsible for searching the HTML text for such placeholders and replacing them with appropriate values before sending the web page to the browser.
String processor(const String& var){
if(var == "STATE"){
return ledState ? "ON" : "OFF";
}
if(var == "CHECK"){
return ledState ? "checked" : "";
}
return String();
}
Read WebSocket messages and broadcasts.
handleWebSocketMessage()
is defined to handle incoming WebSocket messages. When a valid “toggle” is received, it switches the LED, andtextAll()
notifies all connected clients of this change. AsyncWebSockettextAll()
allows the ESP32 to send the same message to all connected clients at the same time, ensuring that the state of the LED is synchronized across all clients.
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
if (strcmp((char*)data, "toggle") == 0) {
ledState = !ledState;
ws.textAll(String(ledState));
}
}
}
Handle server-side WebSocket events. The
ws.onevent(eventHandler)
sets up an event listener for WebSocket. This way, whenever a WebSocket(ws
object)-related event occurs,eventHandler()
is triggered to handle that event.
void eventHandler(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
digitalWrite(ledPin, ledState);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
1-2-10 Web Plotter
1. Overview
Here we will learn how to create a Web plotter that looks similar to a serial plotter in the Arduino IDE, so that we view live data from the ESP32 through a Web browser on your smartphone or PC. It will display the data graphically, just like a serial plotter.
2. Component Knowledge
Web Plotter Working Principle:
ESP32 code creates the Web server and Websocket server. When a user accesses a Web page on the ESP32 board through a browser, the Web server returns content(HTML, CSS, javascript) to the browser.
JavaScript code draws a graph on the browser. When the user clicks the “connect” button, the code creates a Websocket connecting to its server on the board. The ESP32 sends data to the browser via a Websocket in the same format as a serial plotter.
The JavaScript code on the Web browser receives the data and plots it on a graph.
3. Data format that the ESP32 sends to the Web Plotter
To draw multiple variables, we need to separate the variables from each other with the “|t” or “”. The last value must terminate with the “|r|n”.
In detail:
First variable
webSocket.broadcastTXT(variable_1);
Intermediate variable
webSocket.broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket.broadcastTXT(variable_2);
webSocket.broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket.broadcastTXT(variable_3);
Final variable
webSocket.broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket.broadcastTXT(variable_4);
webSocket.broadcastTXT("\r\n"); // the last value is terminated by a carriage return and a newline characters.
4. Quick Description
The content of the web page(HTML, CSS, JavaScript) is stored separately in the index.h file. Therefore, there are two code files on the Arduino IDE:
The .ino file is Web_Plotter code that creates the Web server and Websocket server and controls servo rotation.
The .h file contains the content of the web page.
5. Components
ESP32 main board x1 |
Micro USB cable x1 |
mobile device x1 |
6. Wiring Diagram
7. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Web Plotter
* Function: Draw multiple line plots in the Web server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
// Import required libraries
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>
#include "index.h"
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
AsyncWebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81); // WebSocket server on port 81
int last_update = 0;
void setup() {
Serial.begin(115200);
delay(1000);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize WebSocket server
webSocket.begin();
//webSocket.onEvent(webSocketEvent);
// Serve a basic HTML page with JavaScript to create the WebSocket connection
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
Serial.println("Web Server: received a web page request");
String html = HTML_CONTENT; // Use the HTML content from the index.h file
request->send(200, "text/html", html);
});
server.begin();
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
webSocket.loop();
if (millis() - last_update > 500) {
last_update = millis();
String variable_1 = String(random(0, 100));
String variable_2 = String(random(0, 100));
String variable_3 = String(random(0, 100));
String variable_4 = String(random(0, 100));
// TO SERIAL PLOTTER
// Serial.print(variable_1);
// Serial.print(" "); // a tab '\t' or space ' ' character is printed between the two values.
// Serial.print(variable_2);
// Serial.print(" "); // a tab '\t' or space ' ' character is printed between the two values.
// Serial.print(variable_3);
// Serial.print(" "); // a tab '\t' or space ' ' character is printed between the two values.
// Serial.println(variable_4); // the last value is terminated by a carriage return and a newline characters.
// TO WEB PLOTTER
webSocket.broadcastTXT(variable_1);
webSocket.broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket.broadcastTXT(variable_2);
webSocket.broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket.broadcastTXT(variable_3);
webSocket.broadcastTXT(" "); // a tab '\t' or space ' ' character is printed between the two values.
webSocket.broadcastTXT(variable_4);
webSocket.broadcastTXT("\r\n"); // the last value is terminated by a carriage return and a newline characters.
}
}
8. Create an index.h
In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-10 Web Plotter , open file Web_Plotter.ino directly, and you do not need to create an index.h file, as it is included in the code.
If you copy and pastes the above code into Arduino IDE, you need to create index.h manually:
1. Click the Serial Monitor icon to choose “New Tab”, or press ctrl+shift+N.
2. Input index.h and click “OK”.
3. Copy and paste the following code into index.h .
const char *HTML_CONTENT = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>ESP32 - Web Plotter</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style>
body {text-align: center; height: 750px; }
h1 {font-weight: bold; font-size: 20pt; padding-bottom: 5px; color: navy; }
h2 {font-weight: bold; font-size: 15pt; padding-bottom: 5px; }
button {font-weight: bold; font-size: 15pt; }
#footer {width: 100%; margin: 0px; padding: 0px 0px 10px 0px; bottom: 0px; }
.sub-footer {margin: 0 auto; position: relative; width:400px; }
.sub-footer a {position: absolute; font-size: 10pt; top: 3px; }
</style>
<script>
var COLOR_BACKGROUND = "#FFFFFF";
var COLOR_TEXT = "#000000";
var COLOR_BOUND = "#000000";
var COLOR_GRIDLINE = "#F0F0F0";
//var COLOR_LINE = ["#33FFFF", "#FF00FF", "#FF0000", "#FF8C00", "#00FF00"];
//var COLOR_LINE = ["#0000FF", "#FF0000", "#00FF00", "#FF8C00", "#00FF00"];
//var COLOR_LINE = ["#33FFFF", "#FF0000", "#00FF00", "#FF8C00", "#00FF00"];
var COLOR_LINE = ["#0000FF", "#FF0000", "#009900", "#FF9900", "#CC00CC", "#666666", "#00CCFF", "#000000"];
var LEGEND_WIDTH = 10;
var X_AXIS_TITLE_HEIGHT = 40;
var Y_AXIS_TITLE_WIDTH = 40;
var X_AXIS_VALUE_HEIGHT = 40;
var Y_AXIS_VALUE_WIDTH = 50;
var PLOT_AREA_PADDING_TOP = 30;
var PLOT_AREA_PADDING_RIGHT = 30;
var X_GRIDLINE_NUM = 5;
var Y_GRIDLINE_NUM = 4;
var WSP_SIZE_TYPE = 1; /* 0: Fixed size, 1: full screen */
var WSP_WIDTH = 400;
var WSP_HEIGHT = 200;
var MAX_SAMPLE = 50; // in sample
var X_AXIS_MIN = 0;
var X_AXIS_MAX = MAX_SAMPLE;
var Y_AXIS_AUTO_SCALE = 1; /* 0: y axis fixed range, 1: y axis auto scale */
var Y_AXIS_MIN = -5;
var Y_AXIS_MAX = 5;
var X_AXIS_TITLE = "X";
var Y_AXIS_TITLE = "Y";
var plot_area_width;
var plot_area_height;
var plot_area_pivot_x;
var plot_area_pivot_y;
var sample_count = 0;
var buffer = "";
var data = [];
var ws;
var canvas;
var ctx;
function init()
{
canvas = document.getElementById("graph");
canvas.style.backgroundColor = COLOR_BACKGROUND;
ctx = canvas.getContext("2d");
canvas_resize();
setInterval(update_view, 1000 / 60);
}
function connect_onclick()
{
if(ws == null)
{
ws = new WebSocket("ws://" + window.location.host + ":81");
document.getElementById("ws_state").innerHTML = "CONNECTING";
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
ws.binaryType = "arraybuffer";
}
else
ws.close();
}
function ws_onopen()
{
document.getElementById("ws_state").innerHTML = "<span style='color: blue'>CONNECTED</span>";
document.getElementById("bt_connect").innerHTML = "Disconnect";
}
function ws_onclose()
{
document.getElementById("ws_state").innerHTML = "<span style='color: gray'>CLOSED</span>";
document.getElementById("bt_connect").innerHTML = "Connect";
ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
console.log(e_msg.data);
buffer += e_msg.data;
buffer = buffer.replace(/\r\n/g, "\n");
buffer = buffer.replace(/\r/g, "\n");
while(buffer.indexOf("\n") == 0)
buffer = buffer.substr(1);
if(buffer.indexOf("\n") <= 0)
return;
var pos = buffer.lastIndexOf("\n");
var str = buffer.substr(0, pos);
var new_sample_arr = str.split("\n");
buffer = buffer.substr(pos + 1);
for(var si = 0; si < new_sample_arr.length; si++)
{
var str = new_sample_arr[si];
var arr = [];
if(str.indexOf("\t") > 0)
arr = str.split("\t");
else
arr = str.split(" ");
for(var i = 0; i < arr.length; i++)
{
var value = parseFloat(arr[i]);
if(isNaN(value))
continue;
if(i >= data.length)
{
var new_line = [value];
data.push(new_line); // new line
}
else
data[i].push(value);
}
sample_count++;
}
for(var line = 0; line < data.length; line++)
{
while(data[line].length > MAX_SAMPLE)
data[line].splice(0, 1);
}
if(Y_AXIS_AUTO_SCALE)
auto_scale();
}
function map(x, in_min, in_max, out_min, out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
function get_random_color()
{
var letters = '0123456789ABCDEF';
var _color = '#';
for (var i = 0; i < 6; i++)
_color += letters[Math.floor(Math.random() * 16)];
return _color;
}
function update_view()
{
if(sample_count <= MAX_SAMPLE)
X_AXIS_MAX = sample_count;
else
X_AXIS_MAX = 50;
ctx.clearRect(0, 0, WSP_WIDTH, WSP_HEIGHT);
ctx.save();
ctx.translate(plot_area_pivot_x, plot_area_pivot_y);
ctx.font = "bold 20px Arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = COLOR_TEXT;
// draw X axis title
if(X_AXIS_TITLE != "")
{
ctx.fillText(X_AXIS_TITLE, plot_area_width / 2, X_AXIS_VALUE_HEIGHT + X_AXIS_TITLE_HEIGHT / 2);
}
// draw Y axis title
if(Y_AXIS_TITLE != "")
{
ctx.rotate(-90 * Math.PI / 180);
ctx.fillText(Y_AXIS_TITLE, plot_area_height / 2, -Y_AXIS_VALUE_WIDTH - Y_AXIS_TITLE_WIDTH / 2);
ctx.rotate(90 * Math.PI / 180);
}
ctx.font = "16px Arial";
ctx.textAlign = "right";
ctx.strokeStyle = COLOR_BOUND;
for(var i = 0; i <= Y_GRIDLINE_NUM; i++)
{
var y_gridline_px = -map(i, 0, Y_GRIDLINE_NUM, 0, plot_area_height);
y_gridline_px = Math.round(y_gridline_px) + 0.5;
ctx.beginPath();
ctx.moveTo(0, y_gridline_px);
ctx.lineTo(plot_area_width, y_gridline_px);
ctx.stroke();
ctx.strokeStyle = COLOR_BOUND;
ctx.beginPath();
ctx.moveTo(-7 , y_gridline_px);
ctx.lineTo(4, y_gridline_px);
ctx.stroke();
var y_gridline_value = map(i, 0, Y_GRIDLINE_NUM, Y_AXIS_MIN, Y_AXIS_MAX);
y_gridline_value = y_gridline_value.toFixed(1);
ctx.fillText(y_gridline_value + "", -15, y_gridline_px);
ctx.strokeStyle = COLOR_GRIDLINE;
}
ctx.strokeStyle = COLOR_BOUND;
ctx.textAlign = "center";
ctx.beginPath();
ctx.moveTo(0.5, y_gridline_px - 7);
ctx.lineTo(0.5, y_gridline_px + 4);
ctx.stroke();
for(var i = 0; i <= X_GRIDLINE_NUM; i++)
{
var x_gridline_px = map(i, 0, X_GRIDLINE_NUM, 0, plot_area_width);
x_gridline_px = Math.round(x_gridline_px) + 0.5;
ctx.beginPath();
ctx.moveTo(x_gridline_px, 0);
ctx.lineTo(x_gridline_px, -plot_area_height);
ctx.stroke();
ctx.strokeStyle = COLOR_BOUND;
ctx.beginPath();
ctx.moveTo(x_gridline_px, 7);
ctx.lineTo(x_gridline_px, -4);
ctx.stroke();
var x_gridline_value;
if(sample_count <= MAX_SAMPLE)
x_gridline_value = map(i, 0, X_GRIDLINE_NUM, X_AXIS_MIN, X_AXIS_MAX);
else
x_gridline_value = map(i, 0, X_GRIDLINE_NUM, sample_count - MAX_SAMPLE, sample_count);;
ctx.fillText(x_gridline_value.toString(), x_gridline_px, X_AXIS_VALUE_HEIGHT / 2 + 5);
ctx.strokeStyle = COLOR_GRIDLINE;
}
//ctx.lineWidth = 2;
var line_num = data.length;
for(var line = 0; line < line_num; line++)
{
// draw graph
var sample_num = data[line].length;
if(sample_num >= 2)
{
var y_value = data[line][0];
var x_px = 0;
var y_px = -map(y_value, Y_AXIS_MIN, Y_AXIS_MAX, 0, plot_area_height);
if(line == COLOR_LINE.length)
COLOR_LINE.push(get_random_color());
ctx.strokeStyle = COLOR_LINE[line];
ctx.beginPath();
ctx.moveTo(x_px, y_px);
for(var i = 0; i < sample_num; i++)
{
y_value = data[line][i];
x_px = map(i, X_AXIS_MIN, X_AXIS_MAX -1, 0, plot_area_width);
y_px = -map(y_value, Y_AXIS_MIN, Y_AXIS_MAX, 0, plot_area_height);
ctx.lineTo(x_px, y_px);
}
ctx.stroke();
}
// draw legend
var x = plot_area_width - (line_num - line) * LEGEND_WIDTH - (line_num - line - 1) * LEGEND_WIDTH / 2;
var y = -plot_area_height - PLOT_AREA_PADDING_TOP / 2 - LEGEND_WIDTH / 2;
ctx.fillStyle = COLOR_LINE[line];
ctx.beginPath();
ctx.rect(x, y, LEGEND_WIDTH, LEGEND_WIDTH);
ctx.fill();
}
ctx.restore();
}
function canvas_resize()
{
canvas.width = 0; // to avoid wrong screen size
canvas.height = 0;
if(WSP_SIZE_TYPE)
{ // full screen
document.getElementById('footer').style.position = "fixed";
var width = window.innerWidth - 20;
var height = window.innerHeight - 20;
WSP_WIDTH = width;
WSP_HEIGHT = height - document.getElementById('header').offsetHeight - document.getElementById('footer').offsetHeight;
}
canvas.width = WSP_WIDTH;
canvas.height = WSP_HEIGHT;
ctx.font = "16px Arial";
var y_min_text_size = ctx.measureText(Y_AXIS_MIN.toFixed(1) + "").width;
var y_max_text_size = ctx.measureText(Y_AXIS_MAX.toFixed(1) + "").width;
Y_AXIS_VALUE_WIDTH = Math.round(Math.max(y_min_text_size, y_max_text_size)) + 15;
plot_area_width = WSP_WIDTH - Y_AXIS_VALUE_WIDTH - PLOT_AREA_PADDING_RIGHT;
plot_area_height = WSP_HEIGHT - X_AXIS_VALUE_HEIGHT - PLOT_AREA_PADDING_TOP;
plot_area_pivot_x = Y_AXIS_VALUE_WIDTH;
plot_area_pivot_y = WSP_HEIGHT - X_AXIS_VALUE_HEIGHT;
if(X_AXIS_TITLE != "")
{
plot_area_height -= X_AXIS_TITLE_HEIGHT;
plot_area_pivot_y -= X_AXIS_TITLE_HEIGHT;
}
if(Y_AXIS_TITLE != "")
{
plot_area_width -= Y_AXIS_TITLE_WIDTH;
plot_area_pivot_x += Y_AXIS_TITLE_WIDTH;
}
ctx.lineWidth = 1;
}
function auto_scale()
{
if(data.length >= 1)
{
var max_arr = [];
var min_arr = [];
for(var i = 0; i < data.length; i++)
{
if(data[i].length >= 1)
{
var max = Math.max.apply(null, data[i]);
var min = Math.min.apply(null, data[i]);
max_arr.push(max);
min_arr.push(min);
}
}
var max = Math.max.apply(null, max_arr);
var min = Math.min.apply(null, min_arr);
var MIN_DELTA = 10.0;
if((max - min) < MIN_DELTA)
{
var mid = (max + min) / 2;
max = mid + MIN_DELTA / 2;
min = mid - MIN_DELTA / 2;
}
var range = max - min;
var exp;
if (range == 0.0)
exp = 0;
else
exp = Math.floor(Math.log10(range / 4));
var scale = Math.pow(10, exp);
var raw_step = (range / 4) / scale;
var step;
potential_steps =[1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0];
for (var i = 0; i < potential_steps.length; i++)
{
if (potential_steps[i] < raw_step)
continue;
step = potential_steps[i] * scale;
Y_AXIS_MIN = step * Math.floor(min / step);
Y_AXIS_MAX = Y_AXIS_MIN + step * (4);
if (Y_AXIS_MAX >= max)
break;
}
var count = 5 - Math.floor((Y_AXIS_MAX - max) / step);
Y_AXIS_MAX = Y_AXIS_MIN + step * (count - 1);
ctx.font = "16px Arial";
var y_min_text_size = ctx.measureText(Y_AXIS_MIN.toFixed(1) + "").width;
var y_max_text_size = ctx.measureText(Y_AXIS_MAX.toFixed(1) + "").width;
Y_AXIS_VALUE_WIDTH = Math.round(Math.max(y_min_text_size, y_max_text_size)) + 15;
plot_area_width = WSP_WIDTH - Y_AXIS_VALUE_WIDTH - PLOT_AREA_PADDING_RIGHT;
plot_area_pivot_x = Y_AXIS_VALUE_WIDTH;
}
}
window.onload = init;
</script>
</head>
<body onresize="canvas_resize()">
<h1 id="header">ESP32 - Web Plotter</h1>
<canvas id="graph"></canvas>
<br>
<div id="footer">
<div class="sub-footer">
<h2>WebSocket <span id="ws_state"><span style="color: gray">CLOSED</span></span></h2>
</div>
<button id="bt_connect" type="button" onclick="connect_onclick();">Connect</button>
</div>
</body>
</html>
)=====";
4. There are two code files in the folder: Web_Plotter.ino and index.h .
9. Test Result
Please follow the steps below:
1. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
2. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
3. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
4. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
5. Open the browser on your phone and input the WIFI IP address in it and “search”.
6. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi Web page displays the coordinates of the Web plotter. Meanwhile, the related messages are printed in the serial monitor.
7. Click “Connect” to connect the ESP32 to the web page via Websocket. The data drawn by the plotter is shown below.
⚠️Cautions:
If you modify the HTML content in index.h and haven’t touched anything in the file Web_Plotter.ino , the Arduino IDE won’t update HTML content when you compile and upload the code to ESP32.
To make the Arduino lDE update the HTML content, please make changes in Web_Plotter.ino (e.g. : add blank lines, add comments… And so on).
10. Code Explanation
The code contains line-by-line explanations, please read the comments in the code!
1-2-11 Enter Data on Web Server
1. Overview
In the previous project, we built a Websocket server so not only can we connect to the ESP32 Web Plotter, but we can also input data from the ESP32.
Here we will introduce how to create an Web server with three input fields to pass values to the ESP32 through an HTML form. You can then use these values as variables in your code.
2. Components
ESP32 main board x1 |
Micro USB cable x1 |
mobile device x1 |
3. Wiring Diagram
4. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Enter_Data_on_Web_Server
* Function: Enter data on the HTML form on the ESP32 Web server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80);
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
const char* PARAM_INPUT_1 = "input1";
const char* PARAM_INPUT_2 = "input2";
const char* PARAM_INPUT_3 = "input3";
// HTML web page to handle 3 input fields (input1, input2, input3)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
<title>ESP Input Form</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head><body>
<form action="/get">
input1: <input type="text" name="input1">
<input type="submit" value="Submit">
</form><br>
<form action="/get">
input2: <input type="text" name="input2">
<input type="submit" value="Submit">
</form><br>
<form action="/get">
input3: <input type="text" name="input3">
<input type="submit" value="Submit">
</form>
</body></html>)rawliteral";
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed!");
return;
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// Send web page with input fields to client
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
// Send a GET request to <ESP_IP>/get?input1=<inputMessage>
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
String inputParam;
// GET input1 value on <ESP_IP>/get?input1=<inputMessage>
if (request->hasParam(PARAM_INPUT_1)) {
inputMessage = request->getParam(PARAM_INPUT_1)->value();
inputParam = PARAM_INPUT_1;
}
// GET input2 value on <ESP_IP>/get?input2=<inputMessage>
else if (request->hasParam(PARAM_INPUT_2)) {
inputMessage = request->getParam(PARAM_INPUT_2)->value();
inputParam = PARAM_INPUT_2;
}
// GET input3 value on <ESP_IP>/get?input3=<inputMessage>
else if (request->hasParam(PARAM_INPUT_3)) {
inputMessage = request->getParam(PARAM_INPUT_3)->value();
inputParam = PARAM_INPUT_3;
}
else {
inputMessage = "No message sent";
inputParam = "none";
}
Serial.println(inputMessage);
request->send(200, "text/html", "HTTP GET request sent to your ESP on input field ("
+ inputParam + ") with value: " + inputMessage +
"<br><a href=\"/\">Return to Home Page</a>");
});
server.onNotFound(notFound);
server.begin();
}
void loop() {
}
5. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-11 Enter Data on Web server , open file Enter_Data_on_Web_Server.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. Open the browser on your phone and input the WIFI IP address in it and “search”.
7. After a few seconds, enter the WiFi web page, indicating that the ESP32 module successfully connected to WiFi. The WiFi web page should load as follows:
8. If we input 123456 in the input1 field and click “Submit”, it load a new page, meaning that 123456 is sent to your ESP32 and the serial monitor prints “123456”.
9. Click “Return to Home Page” to return to the previous page. Input AAAA in the input2 field(or input ABC123 in the input3 field) and click “Submit”. Load a new page as shown below. And the serial monitor displays the corresponding messages.
6. Code Explanation
1. HTML forms and input fields. In the example, we show three input fields, each with a “Submit” button. When the user inputs the data and presses the button, the value is sent to the ESP32 and the variable is updated.
// HTML web page to handle 3 input fields (input1, input2, input3)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
<title>ESP Input Form</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head><body>
<form action="/get">
input1: <input type="text" name="input1">
<input type="submit" value="Submit">
</form><br>
<form action="/get">
input2: <input type="text" name="input2">
<input type="submit" value="Submit">
</form><br>
<form action="/get">
input3: <input type="text" name="input3">
<input type="submit" value="Submit">
</form>
</body></html>)rawliteral";
In HTML,
<form>
tag is used to create an HTML form for user input. Here the form should contain an input field and a “submit” button.
2. setup()
connects to your local network.
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("WiFi Failed!");
return;
}
Serial.println();
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
3. Handle HTTP GET requests. When you access the routing URL, the HTML page is sent to the client. In this case, the HTML text will be saved in index_html
.
// Send web page with input fields to client
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
});
1-2-12 Control LED via Web Server
1. Overview
In this project, we will learn to remotely control leds by a Web server and browser on a computer or smartphone. Specifically, the ESP32 will be programmed to work as a Web server. Assume that the lP address of the ESP32 is 192.168.XX.XX. Here’s how it works.
When you access 192.168.XX.XX in your browser, it sends a request to the ESP32 to respond to a web page with an on/off button to control the LED.
Click “Turn ON” in your web pages or input “192.168.XX.XX/1ed1/on” in the browser, the LED turns on and the ESP32 responds to the control page.
Click “Turn OFF” in your web pages or input “192.168.XX.XX/1ed1/off” in the browser, the LED turns off and the ESP32 responds to the control page.
2. Components
ESP32 main board x1 |
red LED x1 |
220Ω resistor x1 |
mobile device x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Control_LED_Via_Web_Server
* Function: Control the LED on and off through the Web Server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#define LED_PIN 26 // ESP32 pin GPIO26 connected to LED
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
AsyncWebServer server(80);
int LED_state = LOW;
String getHTML() {
String html = "<!DOCTYPE HTML>";
html += "<html>";
html += "<head>";
html += "<link rel='icon' href='data:,'>";
html += "</head>";
html += "<p>LED state: <span style='color: red;'>";
if (LED_state == LOW)
html += "OFF";
else
html += "ON";
html += "</span></p>";
html += "<a href='/led1/on'>Turn ON</a>";
html += "<br><br>";
html += "<a href='/led1/off'>Turn OFF</a>";
html += "</html>";
return html;
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LED_state);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Print the ESP32's IP address
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
// home page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("ESP32 Web Server: New request received:");
Serial.println("GET /");
request->send(200, "text/html", getHTML());
});
// Route to control the LED
server.on("/led1/on", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("ESP32 Web Server: New request received:");
Serial.println("GET /led1/on");
LED_state = HIGH;
digitalWrite(LED_PIN, LED_state);
request->send(200, "text/html", getHTML());
});
server.on("/led1/off", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("ESP32 Web Server: New request received:");
Serial.println("GET /led1/off");
LED_state = LOW;
digitalWrite(LED_PIN, LED_state);
request->send(200, "text/html", getHTML());
});
// Start the server
server.begin();
}
void loop() {
// Your code here
}
5. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-12 Control LED Via Web Server , open file Control_LED_Via_Web_Server.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. Open the browser on your phone and input the WIFI IP address in it and “search”.
7. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page contains an on/off button for the LED and “LED state: OFF”. Meanwhile, the related messages are printed in the serial monitor.
8. Click “Turn ON” to turn on the LED, and “LED state: OFF” becomes “LED state: ON”. At the same time, the serial monitor prints corresponding messages.
9. Click “Turn OFF” to turn off the LED, and “LED state: ON” becomes “LED state: OFF”. At the same time, the serial monitor prints corresponding messages.
6. Code Explanation
The code contains line-by-line explanations, please read the comments in the code!
1-2-13 Control Relay via Web Server
1. Overview
In this project, we will learn to remotely control the relay by a Web server and browser on a computer or smartphone. Specifically, the ESP32 will be programmed to work as a Web server. Assume that the lP address of the ESP32 is 192.168.XX.XX. Here’s how it works.
When you access 192.168.XX.XX in your browser, it sends a request to the ESP32 to respond to a web page with an on/off button to control the LED.
Click “Turn ON” in your web pages or input “192.168.XX.XX/1ed1/on” in the browser, the relay turns on and the ESP32 responds to the control page.
Click “Turn OFF” in your web pages or input “192.168.XX.XX/1ed1/off” in the browser, the relay turns off and the ESP32 responds to the control page.
2. Components
ESP32 main board x1 |
breadboard x1 |
mobile device x1 |
relay x1 |
LED x1 |
220Ω resistor x1 |
jumper wires |
Micro USB cable x1 |
M-F DuPont wires |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Control Relay Via Web Server
* Function : Relay connecting and disconnecting are controlled through the Web server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#define relayPin 12 // ESP32 pin GPIO12 connected to Relay
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
AsyncWebServer server(80);
int relay_state = LOW;
String getHTML() {
String html = "<!DOCTYPE HTML>";
html += "<html>";
html += "<head>";
html += "<link rel='icon' href='data:,'>";
html += "</head>";
html += "<p>Relay state: <span style='color: red;'>";
if (relay_state == LOW)
html += "OFF";
else
html += "ON";
html += "</span></p>";
html += "<a href='/relay1/on'>Turn ON</a>";
html += "<br><br>";
html += "<a href='/relay1/off'>Turn OFF</a>";
html += "</html>";
return html;
}
void setup() {
Serial.begin(115200);
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, relay_state);
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Print the ESP32's IP address
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
// home page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("ESP32 Web Server: New request received:");
Serial.println("GET /");
request->send(200, "text/html", getHTML());
});
// Route to control the Relay
server.on("/relay1/on", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("ESP32 Web Server: New request received:");
Serial.println("GET /relay1/on");
relay_state = HIGH;
digitalWrite(relayPin, relay_state);
request->send(200, "text/html", getHTML());
});
server.on("/relay1/off", HTTP_GET, [](AsyncWebServerRequest *request) {
Serial.println("ESP32 Web Server: New request received:");
Serial.println("GET /relay1/off");
relay_state = LOW;
digitalWrite(relayPin, relay_state);
request->send(200, "text/html", getHTML());
});
// Start the server
server.begin();
}
void loop() {
// Your code here
}
5. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-13 Control Relay Via Web Server , open file Control_Relay_Via_Web_Server.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. Open the browser on your phone and input the WIFI IP address in it and “search”.
7. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page contains an on/off button for the relay and “Relay state: OFF”. Meanwhile, the related messages are printed in the serial monitor.
8. Click “Turn ON” to close the relay and the LED lights up. “Relay state: OFF” becomes “Relay state: ON”. At the same time, the serial monitor prints corresponding messages.
9. Click “Turn OFF” to open the relay and the LED goes off. “Relay state: ON” becomes “Relay state: OFF”. At the same time, the serial monitor prints corresponding messages.
6. Code Explanation
The code contains line-by-line explanations, please read the comments in the code!
1-2-14 Control Servo Via Web Server
1. Overview
Here we create a Web server to remotely control the servo with a Web server on a smartphone or computer. We use a programmable Web platform called Websocket to smoothly and dynamically control servo rotation.
Why a Websocket?
Without Websockets, you have to reload the page every time you want to change servo angle. It’s not convenient!
With Websocket, a special connection is established between the web page and the ESP32. This means that we can send the angle value to the ESP32 in the background without reloading. This allows servo to move smoothly in real time. Isn’t that cool?
2. Component Knowledge
Working principle:
ESP32 code creates both a Web server and a Websocket server. Here’s how it works:
When you input the IP address in your browser, it requests a web page from the ESP32 (user interface). ESP32 Web server responds by sending web content (HTML, CSS, JavaScript).
Your Web browser will then display the web page.
The JavaScript code in the web page establishes a connection with the Websocket server on the ESP32.
After that, if you turn the servo axis on the web page, JavaScript code sends the angle value to the ESP32 through this connection in the background.
The Websocket server on the ESP32 receives the Angle value and controls the servo accordingly.
In short, Websocket connections allow smooth, real-time control of servo’s angle.
3. Quick Description
The content of the web page(HTML, CSS, JavaScript) is stored separately in the index.h file. Therefore, there are two code files on the Arduino IDE:
The .ino file is ESP32 code that creates the Web server and Websocket server.
The .h file contains the content of the web page.
4. Components
ESP32 main board x1 |
servo x1 |
Micro USB cable x1 |
mobile device x1 |
5. Wiring Diagram
Schematic diagram:
Wiring diagram:
6. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Control_Servo_Via_Web_Server
* Function: Control the servo rotation through the Web server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <ESP32Servo.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>
#include "index.h"
// Define the servo and the pin it is connected to
Servo myServo;
const int servoPin = 4;
// Define the minimum and maximum pulse widths for the servo
const int minPulseWidth = 500; // 0.5 ms
const int maxPulseWidth = 2500; // 2.5 ms
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
AsyncWebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81); // WebSocket server on port 81
void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
switch (type) {
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("[%u] Connected from %d.%d.%d.%d\n", num, ip[0], ip[1], ip[2], ip[3]);
}
break;
case WStype_TEXT:
//Serial.printf("[%u] Received text: %s\n", num, payload);
String angle = String((char*)payload);
int angle_value = angle.toInt();
Serial.println(angle_value);
myServo.write(angle_value);
break;
}
}
void setup() {
Serial.begin(115200);
// Attach the servo to the specified pin and set its pulse width range
myServo.attach(servoPin, minPulseWidth, maxPulseWidth);
// Set the PWM frequency for the servo
myServo.setPeriodHertz(50); // Standard 50Hz servo
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize WebSocket server
webSocket.begin();
webSocket.onEvent(webSocketEvent);
// Serve a basic HTML page with JavaScript to create the WebSocket connection
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
Serial.println("Web Server: received a web page request");
String html = HTML_CONTENT; // Use the HTML content from the index.h file
request->send(200, "text/html", html);
});
server.begin();
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
webSocket.loop();
}
7. Create an index.h
In folder …\Codes\Arduino_C_Code\IoT_C_Code\14 Control Servo Via Web Server , open file Control_Servo_Via_Web_Server.ino directly, and you do not need to create an index.h file, as it is included in the code.
If you copy and pastes the above code into Arduino IDE, you need to create index.h manually:
1. Click the Serial Monitor icon to choose “New Tab”, or press ctrl+shift+N.
2. Input index.h and click “OK”.
3. Copy and paste the following code into index.h .
const char *HTML_CONTENT = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>ESP32 Controls Servo Motor via Web</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style>
body { text-align: center; }
canvas { background-color: #ffffff; }
</style>
<script>
var canvas_width = 401, canvas_height = 466;
var pivot_x = 200, pivot_y = 200;
var bracket_radius = 160, bracket_angle = 0;
var bracket_img = new Image();
var click_state = 0;
var last_angle = 0;
var mouse_xyra = {x:0, y:0, r:0.0, a:0.0};
var ws;
bracket_img.src = "https://esp32io.com/images/tutorial/servo-bracket.png";
function init()
{
var servo = document.getElementById("servo");
servo.width = canvas_width;
servo.height = canvas_height;
servo.style.backgroundImage = "url('https://esp32io.com/images/tutorial/servo-body.png')";
servo.style.backgroundPosition = "center";
servo.style.backgroundSize = "contain";
servo.addEventListener("touchstart", mouse_down);
servo.addEventListener("touchend", mouse_up);
servo.addEventListener("touchmove", mouse_move);
servo.addEventListener("mousedown", mouse_down);
servo.addEventListener("mouseup", mouse_up);
servo.addEventListener("mousemove", mouse_move);
var ctx = servo.getContext("2d");
ctx.translate(pivot_x, pivot_y);
rotate_bracket(0);
ws = new WebSocket("ws://" + window.location.host + ":81");
document.getElementById("ws_state").innerHTML = "CONNECTING";
ws.onopen = function(){ document.getElementById("ws_state").innerHTML = "CONNECTED" };
ws.onclose = function(){ document.getElementById("ws_state").innerHTML = "CLOSED"};
ws.onerror = function(){ alert("websocket error " + this.url) };
ws.onmessage = ws_onmessage;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
alert("msg : " + e_msg.data);
}
function rotate_bracket(angle)
{
var servo = document.getElementById("servo");
var ctx = servo.getContext("2d");
ctx.clearRect(-pivot_x, -pivot_y, canvas_width, canvas_height);
ctx.rotate(angle / 180 * Math.PI);
ctx.drawImage(bracket_img, -pivot_x, -pivot_y);
ctx.rotate(-angle / 180 * Math.PI);
}
function check_range_xyra(event, mouse_xyra)
{
var x, y, r, a, rc_x, rc_y, radian;
var min_r, max_r, width;
if(event.touches)
{
var touches = event.touches;
x = (touches[0].pageX - touches[0].target.offsetLeft) - pivot_x;
y = pivot_y - (touches[0].pageY - touches[0].target.offsetTop);
min_r = 60;
max_r = pivot_x;
width = 40;
}
else
{
x = event.offsetX - pivot_x;
y = pivot_y - event.offsetY;
min_r = 60;
max_r = bracket_radius;
width = 20;
}
/* cartesian to polar coordinate conversion */
r = Math.sqrt(x * x + y * y);
a = Math.atan2(y, x);
mouse_xyra.x = x;
mouse_xyra.y = y;
mouse_xyra.r = r;
mouse_xyra.a = a;
radian = bracket_angle / 180 * Math.PI;
/* rotate coordinate */
rc_x = x * Math.cos(radian) - y * Math.sin(radian);
rc_y = x * Math.sin(radian) + y * Math.cos(radian);
if((r < min_r) || (r > max_r))
return false;
if((rc_y < -width) || (rc_y > width))
return false;
return true;
}
function mouse_down()
{
if(event.touches && (event.touches.length > 1))
click_state = event.touches.length;
if(click_state > 1)
return;
if(check_range_xyra(event, mouse_xyra))
{
click_state = 1;
last_angle = mouse_xyra.a / Math.PI * 180.0;
}
}
function mouse_up()
{
click_state = 0;
}
function mouse_move()
{
var angle;
if(event.touches && (event.touches.length > 1))
click_state = event.touches.length;
if(click_state > 1)
return;
if(!click_state)
return;
if(!check_range_xyra(event, mouse_xyra))
{
click_state = 0;
return;
}
angle = mouse_xyra.a / Math.PI * 180.0;
if((Math.abs(angle) > 90) && (angle * last_angle < 0))
{
if(last_angle > 0)
last_angle = -180;
else
last_angle = 180;
}
bracket_angle += (last_angle - angle);
last_angle = angle;
if(bracket_angle > 90)
bracket_angle = 90;
if(bracket_angle < -90)
bracket_angle = -90;
rotate_bracket(bracket_angle);
if(ws.readyState == 1)
ws.send(Math.floor(90 - bracket_angle) + "\r\n");
debug = document.getElementById("debug");
debug.innerHTML = Math.floor(90 - bracket_angle);
event.preventDefault();
}
window.onload = init;
</script>
</head>
<body>
<h2>
ESP32 - Servo Motor via Web<br>
<canvas id="servo"></canvas>
<p>
WebSocket : <span id="ws_state" style="color:blue">null</span><br>
Angle : <span id="debug" style="color:blue">90</span>
</p>
</h2>
<div class="sponsor">Sponsored by <a href="https://keyestudio.com/diyables">DIYables</a></div>
</body>
</html>
)=====";
4. Now there are two code files in the folder: Web_Plotter.ino and index.h 。
8. Test Result
Please follow the steps below:
1. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
2. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
3. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
4. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
5. Open the browser on your phone and input the WIFI IP address in it and “search”.
6. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page displays the servo-related messages and servo initial angles. Meanwhile, the related messages are printed in the serial monitor.
7. We control servo angle through the Web interface, that is, rotate the servo axis on the smartphone by your hand, and the servo angle value will change accordingly. At the same time, the serial monitor prints the value, and the servo will also rotate accordingly.
9. Code Explanation
The code contains line-by-line explanations, please read the comments in the code!
1-2-15 Control Stepper Motor Via Web Server
1. Overview
In the previous project, we learned how to create a Web server to remotely control servo rotation. Here we will learn how to remotely control the stepper motor. The Web server displays a web page with an HTML form that allows you to select the direction and number of steps of the stepper motor.
2. Working Principle
On the web page, you can choose whether to rotate the Stepper motor clockwise or counterclockwise. These are radio buttons, usually shown as small circles, which are filled or highlighted when selected. You can choose only one in a given group at a time.
There is an input field of type number where the user can enter numbers. Here is steps. Another button is called “GO!” and of type submit. It sends data to the server through an HTTP POST request.
3. Components
ESP32 main board x1 |
ULN2003 stepper motor drive board x1 |
Stepper motor x1 |
battery holder x1 |
M-F DuPont wires |
AA battery (self-provided) x6 |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Control Stepper Motor Via Web Server
* Function: The ESP32 Web server controls the stepper motor
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>
// Stepper Motor Settings
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution
#define IN1 16
#define IN2 17
#define IN3 18
#define IN4 19
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Search for parameters in HTTP POST request
const char* PARAM_INPUT_1 = "direction";
const char* PARAM_INPUT_2 = "steps";
// Variables to save values from HTML form
String direction;
String steps;
// Variable to detect whether a new request occurred
bool newRequest = false;
// HTML to build the web page
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Stepper Motor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Stepper Motor Control</h1>
<form action="/" method="POST">
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
<label for="steps">Number of steps:</label>
<input type="number" name="steps">
<input type="submit" value="GO!">
</form>
</body>
</html>
)rawliteral";
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initWiFi();
myStepper.setSpeed(5);
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", index_html);
});
// Handle request (form)
server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
int params = request->params();
for(int i=0;i<params;i++){
const AsyncWebParameter* p = request->getParam(i);
if(p->isPost()){
// HTTP POST input1 value (direction)
if (p->name() == PARAM_INPUT_1) {
direction = p->value().c_str();
Serial.print("Direction set to: ");
Serial.println(direction);
}
// HTTP POST input2 value (steps)
if (p->name() == PARAM_INPUT_2) {
steps = p->value().c_str();
Serial.print("Number of steps set to: ");
Serial.println(steps);
}
}
}
request->send(200, "text/html", index_html);
newRequest = true;
});
server.begin();
}
void loop() {
// Check if there was a new request and move the stepper accordingly
if (newRequest){
if (direction == "CW"){
// Spin the stepper clockwise direction
myStepper.step(-steps.toInt());
}
else{
// Spin the stepper counterclockwise direction
myStepper.step(steps.toInt());
}
newRequest = false;
}
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-15 Control Stepper Motor Via Web Server , open file Control_Stepper_Motor_Via_Web_Server.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. Open the browser on your phone and input the WIFI IP address in it and “search”.
7. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page shows the following content.
8. Tick Clockwise and input 2000. Click “GO!” and the stepper motor rotates clockwise.
9. Tick Counterclockwise and input 2000. Click “GO!” and the stepper motor rotates counter-clockwise.
7. Code Explanation
1. The clicked radio button
Definition:
<input type="radio">
Two radio buttons are required here, and only one can be selected at a time. Therefore, you can create a set of radio buttons that share the same name(here is direction).
<input type="radio" name="direction">
Here value type is required too. It is a unique value specified for each radio button and is not visible to the user. Yet, click “GO!” to identify which button is selected, and it will be sent to the server. Here we create CW (clockwise rotation) and CCW (counter-clockwise rotation).
<input type="radio" name="direction" value="CW">
<input type="radio" name="direction" value="CCW">
If you want to select a radio button by default, you can add
checked
keyword. By default, clockwise direction is selected here.
<input type="radio" name="direction" value="CW" checked>
Radio buttons and corresponding labels look like this.
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
2. Input field (number of steps).
An input field is required where the user can enter the number of steps - an input field number of numeric type. The
name
determines which input field the user entered the data in.
<input type="number" name="steps">
3. Submit button
To fill out the form, you also need a submit button. It is an input submit
. Click it to send data to the server(ESP32 main board). The value
specifies the text to be displayed on the button.
<input type="submit" value="GO!">
If you select clockwise and enter 2000 steps, the client will make the following request to the ESP32:
POST /
Host: localhost
direction=CW&steps=2000
The ESP receives the request and can get the direction and number of steps from the request.
1-2-16 Temperature from LM35 on Web Server
1. Overview
In this project, we will explore the process of programming ESP32 as a web server to access temperature values. With the LM35 temperature sensor, it is easy to check the ambient temperature on the web page of your smartphone or computer.
2. Component Knowledge
Working principle:
ESP32 is programmed as a Web server.
You can enter the iP address of the ESP32 into a Web browser on your smartphone or PC.
The ESP32 responds to a request from a Web browser to form a page where the LM35 temperature sensor reads the temperature.
3. Quick Description
The content of the web page(HTML, CSS, JavaScript) is stored separately in the index.h file. Therefore, there are two code files on the Arduino IDE:
The .ino file is ESP32 code that creates the Web server and Websocket server.
The .h file contains the content of the web page.
4. Components
ESP32 main board x1 |
LM35 x1 |
breadboard x1 |
jumper wires |
USB cable x1 |
mobile device x1 |
5. Wiring Diagram
Schematic diagram:
Wiring diagram:
6. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Temperature from LM35 on Web Server
* Function: The LM35 detected temperature is displayed on the Web server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
// Import required libraries
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>
#include "index.h"
const int lm35Pin = 36; // ESP32 pin GPIO36 connected to LM35 sensor's DATA pin
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
AsyncWebServer server(80);
void setup() {
Serial.begin(115200);
pinMode(lm35Pin, INPUT); //Set the lm35Pin to the input mode
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Print the ESP32's IP address
Serial.print("ESP32 Web Server's IP address: ");
Serial.println(WiFi.localIP());
// Serve the HTML page from the file
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
Serial.println("ESP32 Web Server: New request received:"); // for debugging
Serial.println("GET /"); // for debugging
request->send(200, "text/html", webpage); // webpage is from index.h file
}); // for debugging
// Define a route to get the temperature data
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest* request) {
Serial.println("ESP32 Web Server: New request received:"); // for debugging
Serial.println("GET /temperature");
long value = analogRead(lm35Pin); //Read analog input
// get temperature from sensor
// Voltage and Celsius conversion:
// 0.0012210012210012 = 5.0/4095, 0~5.0V corresponds to the analog port reading 0~4095, and every 10 millivolts corresponds to 1℃
float temperature = (value * 0.0012210012210012 * 100);
// Format the temperature with two decimal places
String temperatureStr = String(temperature, 2);
request->send(200, "text/plain", temperatureStr);
});
// Start the server
server.begin();
}
void loop() {
// Your code here
}
7. Create an index.h
In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-16 Temperature from LM35 on Web Server , open file Temperature_from_LM35_on_Web_Server.ino directly, and you do not need to create an index.h file, as it is included in the code.
If you copy and pastes the above code into Arduino IDE, you need to create index.h manually:
1. Click the Serial Monitor icon to choose “New Tab”, or press ctrl+shift+N.
2. Input index.h and click “OK”.
3. Copy and paste the following code into index.h .
#ifndef WEBPAGE_H
#define WEBPAGE_H
const char* webpage = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>ESP32 - Web Temperature</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<link rel="icon" href="https://diyables.io/images/page/diyables.svg">
<style>
body { font-family: "Georgia"; text-align: center; font-size: width/2pt;}
h1 { font-weight: bold; font-size: width/2pt;}
h2 { font-weight: bold; font-size: width/2pt;}
button { font-weight: bold; font-size: width/2pt;}
</style>
<script>
var cvs_width = 200, cvs_height = 450;
function init() {
var canvas = document.getElementById("cvs");
canvas.width = cvs_width;
canvas.height = cvs_height + 50;
var ctx = canvas.getContext("2d");
ctx.translate(cvs_width/2, cvs_height - 80);
fetchTemperature();
setInterval(fetchTemperature, 4000); // Update temperature every 4 seconds
}
function fetchTemperature() {
fetch("/temperature")
.then(response => response.text())
.then(data => {update_view(data);});
}
function update_view(temp) {
var canvas = document.getElementById("cvs");
var ctx = canvas.getContext("2d");
var radius = 70;
var offset = 5;
var width = 45;
var height = 330;
ctx.clearRect(-cvs_width/2, -cvs_height + 80, cvs_width, cvs_height + 50);
ctx.strokeStyle="blue";
ctx.fillStyle="blue";
//5-step Degree
var x = -width/2;
ctx.lineWidth=2;
for (var i = 0; i <= 100; i+=5) {
var y = -(height - radius)*i/100 - radius - 5;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x - 20, y);
ctx.stroke();
}
//20-step Degree
ctx.lineWidth=5;
for (var i = 0; i <= 100; i+=20) {
var y = -(height - radius)*i/100 - radius - 5;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x - 25, y);
ctx.stroke();
ctx.font="20px Georgia";
ctx.textBaseline="middle";
ctx.textAlign="right";
ctx.fillText(i.toString(), x - 35, y);
}
// shape
ctx.lineWidth=16;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.rect(-width/2, -height, width, height);
ctx.stroke();
ctx.beginPath();
ctx.arc(0, -height, width/2, 0, 2 * Math.PI);
ctx.stroke();
ctx.fillStyle="#e6e6ff";
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.rect(-width/2, -height, width, height);
ctx.fill();
ctx.beginPath();
ctx.arc(0, -height, width/2, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle="#ff1a1a";
ctx.beginPath();
ctx.arc(0, 0, radius - offset, 0, 2 * Math.PI);
ctx.fill();
temp = Math.round(temp * 100) / 100;
var y = (height - radius)*temp/100.0 + radius + 5;
ctx.beginPath();
ctx.rect(-width/2 + offset, -y, width - 2*offset, y);
ctx.fill();
ctx.fillStyle="red";
ctx.font="bold 34px Georgia";
ctx.textBaseline="middle";
ctx.textAlign="center";
ctx.fillText(temp.toString() + "°C", 0, 100);
}
window.onload = init;
</script>
</head>
<body>
<h1>ESP32 - Web Temperature</h1>
<canvas id="cvs"></canvas>
</body>
</html>
)=====";
#endif
4. Now there are two code files in the folder: Web_Plotter.ino and index.h.
8. Test Result
Please follow the steps below:
1. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
2. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
3. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
4. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
5. Open the browser on your phone and input the WIFI IP address in it and “search”.
6. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page shows the temperature value. Meanwhile, the related messages are printed in the serial monitor.
7. If the ambient temperature detected by the LM35 sensor is constantly changed, the value displayed on the web page will also change. Meanwhile, the related messages are printed in the serial monitor.
9. Code Explanation
The code contains line-by-line explanations, please read the comments in the code!
1-2-17 Display XHT11 Values Using Web Server
1. Overview
Have you ever wished you could monitor the temperature and humidity in your home, cooler or wine cellar at all times by your smartphone, tablet, or computer? This IoT project might be a good place to start!
We use the ESP32 as the control device to connect to the existing WiFi network and create a Web server. When the device is connected to this server, the ESP32 will read the temperature and relative humidity from the DHT11 sensor and send it to browser of the mobile device.
2. Components
ESP32 main board x1 |
DHT11 temperature and humidity sensor x1 |
jumper wires |
breadboard x1 |
mobile device x1 |
Micro USB cable x1 |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Display Values of XHT11 Using Web Server
* Function: Connect the DHT11 to the ESP32 and display the values using the Web server
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <WiFi.h>
#include <WebServer.h>
#include "DHT.h"
// Uncomment one of the lines below for whatever DHT sensor type you're using!
#define DHTTYPE DHT11 // DHT 11
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
WebServer server(80);
// Set the 1O13 connected to the DHT11 data pin
uint8_t DHTPin = 13;
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);
float Temperature;
float Humidity;
void setup() {
Serial.begin(115200);
delay(100);
pinMode(DHTPin, INPUT);
dht.begin();
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
}
void handle_OnConnect() {
Temperature = dht.readTemperature(); // Gets the values of the temperature
Humidity = dht.readHumidity(); // Gets the values of the humidity
server.send(200, "text/html", SendHTML(Temperature, Humidity));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(float TempCstat,float Humiditystat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";
ptr +="<title>ESP32 Weather Report</title>\n";
ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
ptr +="body{margin-top: 50px;}\n";
ptr +="h1 {margin: 50px auto 30px;}\n";
ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
ptr +=".data{padding: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP32 Weather Report</h1>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side temperature-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side temperature-text\">Temperature</div>\n";
ptr +="<div class=\"side-by-side temperature\">";
ptr +=(int)TempCstat;
ptr +="<span class=\"superscript\">'C</span></div>\n";
ptr +="</div>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side humidity-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side humidity-text\">Humidity</div>\n";
ptr +="<div class=\"side-by-side humidity\">";
ptr +=(int)Humiditystat;
ptr +="<span class=\"superscript\"> % </span></div>\n";
ptr +="</div>\n";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
5. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-17 Display XHT11 Values Using Web Server , open the file XHT11_Values_Using_Web_Server.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. Open the browser on your phone and input the WIFI IP address in it and “search”.
7. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page shows the following content.
8. If the ambient temperature and humidity detected by the DHT11 sensor, click the “” and the values displayed on the web page will be updated.
6. Code Explanation
Let’s explain the code in details:
Include
WiFi.h
library. The library contains the specific methods we used to connect the ESP32 to the network; TheWebServer.h
also contains methods that will help us configure the server and process incoming HTTP requests.Finally, include the DHT.h library.
#include <WiFi.h>
#include <WebServer.h>
#include "DHT.h"
Specifie the type of DHT sensor.
#define DHTTYPE DHT11 // DHT 11
Since we configured the ESP32 Web server in Station mode, it will create its own WiFi network. Therefore, we need to set our SSID and Password.
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
Create
WebServer
library instance to access its functions that accepts the port on which the server will listen as a parameter. Since HTTP uses port 80 by default, this value will be adopted. This allows us to connect to the server without specifying a port in the URL.
// declare an object of WebServer library
WebServer server(80);
On the ESP32 connected to the sensor S pin, define the GPIO pin number and create a DHT object. Therefore, we have access to the DHT functions.
// Set the 1O13 connected to the DHT11 data pin
uint8_t DHTPin = 13;
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);
Two floating point variables are set: Temperature and Humidity.
float Temperature;
float Humidity;
setup()
configures the Web server. We first set up a serial connections for debugging and configure the GPIO pin to INPUT. Initialize the DHT object.
Serial.begin(115200);
delay(100);
pinMode(DHTPin, INPUT);
dht.begin();
When the ESP32 tries to connect to the network, we use
WiFi.status()
to check the connection status.
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Once connected to the network,
WiFi.localIP()
prints the IP address of the ESP32.
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
In order to handle incoming HTTP requests, we must specify what code should be executed when accessing a particular URL. Therefore,
.on()
is used. It takes two parameters: a relative URL path and the name of the function to execute when accessing that URL.For example, the first line of the following code indicates that the server will call the function
handle_OnConnect()
when it receives an HTTP request on the root (/) path. However, note that the specified URL is a relative path.Similarly, we must specify four more URLs to handle the two states of the two leds.
server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);
If the URL requested by the client is not specified by
server.on()
, and we haven’t specified what service the server should provide, it should response a 404 error (Page Not Found). Therefore,server.onNotFound()
is adopted.
server.onNotFound(handle_NotFound);
begin() of the server object starts the server.
server.begin();
Serial.println("HTTP server started");
The actual incoming HTTP request is processed in
loop()
. Therefore, we usehandleClient()
. We also change the state of the led upon request.
void loop() {
server.handleClient();
if(LED1status)
{digitalWrite(LED1pin, HIGH);}
else
{digitalWrite(LED1pin, LOW);}
if(LED2status)
{digitalWrite(LED2pin, HIGH);}
else
{digitalWrite(LED2pin, LOW);}
}
handle_OnConnect()
must be written. Theserver.on
appended it to the root (/) URL before. We set the status of both leds to LOW (the initial states) and print them on the serial monitor to enable this function.“send” responds to the HTTP request. Although this method can be invoked with many different parameters, it is easiest to use the HTTP response code, content type, and content. The first parameter passed to “send” is the code 200 (one of the HTTP status codes), which corresponds to the OK response. Then we set the content type to “text/html” and pass custom function
SendHTML()
to generate dynamic html pages with LED status.
void handle_OnConnect() {
LED1status = LOW;
LED2status = LOW;
Serial.println("GPIO17 Status: OFF | GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,LED2status));
}
Five functions were written to handle LED on/off requests and 404 error pages.
void handle_led1on() {
LED1status = HIGH;
Serial.println("GPIO17 Status: ON");
server.send(200, "text/html", SendHTML(true,LED2status));
}
void handle_led1off() {
LED1status = LOW;
Serial.println("GPIO17 Status: OFF");
server.send(200, "text/html", SendHTML(false,LED2status));
}
void handle_led2on() {
LED2status = HIGH;
Serial.println("GPIO13 Status: ON");
server.send(200, "text/html", SendHTML(LED1status,true));
}
void handle_led2off() {
LED2status = LOW;
Serial.println("GPIO13 Status: OFF");
server.send(200, "text/html", SendHTML(LED1status,false));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
Display HTML web pages. When the ESP32 Web server receives a request from a Web client,
SendHTML()
generates a Web page. It simply concatenates the HTML code into a long string and returns it toserver.send()
. This function uses the state of the led as a parameter to dynamically generate HTML content. The first text you should send is always <!DOCTYPE> declaration, meaning that HTML code is being sent.
String SendHTML(uint8_t led1stat,uint8_t led2stat){
String ptr = "<!DOCTYPE html> <html>\n";
viewport element makes the web page responsive, ensuring that it looks good on all devices. The title tag determines the title of the page.
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";
Design the web page style. We use CSS to design the buttons and the overall look of the page. We selected the Helvetica font and defined the content displayed as inline blocks, centered.
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
Set the colors around the body, H1, H3, and p tags, set the fonts and margins.
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
These buttons can also be styled by colosr, sizes, margins and so on. :active selector changes the appearance of the button when it is pressed.
ptr +=".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #3498db;}\n";
ptr +=".button-on:active {background-color: #2980b9;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";
Set the title of the page. You can change this text to anything that suits your application.
ptr +="<h1>ESP32 Web Server</h1>\n";
ptr +="<h3>Using Station(STA) Mode</h3>\n";
Display buttons and their status. The if statement is used to dynamically update the status of buttons and leds.
if(led1stat)
{ptr +="<p>LED1 Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
{ptr +="<p>LED1 Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}
if(led2stat)
{ptr +="<p>LED2 Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
{ptr +="<p>LED2 Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}
1-2-18 Internet Clock with ESP32 and OLED
1. Overview
In the previous experiments, we learned about the WiFi of the ESP32. The ESP32 is a Wi-Fi module that is easy to connect to the Internet, so we will use NTP (Network Time Protocol) and UDP (User Datagram Protocol) to get time from the Internet over Wi-Fi. To minimize hardware requirements, we do not adopt a clock module. This Internet clock is very useful in IoT projects.
2. Component Knowledge
What is NTP?
Network time protocol(NTP) is used to synchronize time between the system and the data network and can precisely adjust the time of day. The NTP framework relies on Internet Time servers. NTP server comes with software that sends the clock time to the client computer via UDP port 123.
So, in this project, we take the time from the NTP server and display it on the OLED.
3. Components
ESP32 main board x1 |
OLED x1 |
F-F DuPont wires |
USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
You also need to change the following three variables in the code based on your country’s time zone:
NTP_OFFSET is the time zone of your country/region. For example: it is now + 5:30 in India, so it is 19800 (5.5 × 3600) seconds.
NTP_INTERVAL is the time interval used by the NTP update time, which is 60 ~ 64 seconds. Here we take 60 seconds as an example.
NTP_ADDRESS is the NTP server for your country. For instance, Indian users adopt “
in.pool.ntp.org
”.
/*
* Filename: Internet Clock with ESP32 and OLED
* Function: Internet clock with ESP32 and OLED display
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <WiFi.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
#define NTP_OFFSET 19800 // In seconds
#define NTP_INTERVAL 60 * 1000 // In miliseconds
#define NTP_ADDRESS "1.asia.pool.ntp.org"
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup(){
display.begin();
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
timeClient.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialization with I2C addr 0x3C (for 128x64)
display.clearDisplay(); // clear display
display.setTextColor(WHITE);
//display.startscrollright(0x00, 0x0F);
display.setTextSize(2);
//display.setCursor(0,0);
//display.print(" Internet ");
//display.println(" Clock ");
//display.display();
//delay(3000);
}
void loop(){
timeClient.update();
String formattedTime = timeClient.getFormattedTime();
// Serial.println(formattedTime);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.println(formattedTime);
display.display(); // write the buffer to the display
delay(10);
delay(100);
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-18 Internet Clock with ESP32 and OLED , open the file Internet_Clock_with_ESP32_and_OLED.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. The OLED shows your Internet clock.
7. Code Explanation
Contain all the libraries and define variables for entering the Wi-Fi name and password.
#include <WiFi.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
NTPClient.h
is used to connect to the time server and requires NTP server time to keep it synchronized.Hhre WiFiUdp.h
is used to send and receive UDP messages. UDP is a protocol for sending and receiving short messages from our system to the NTP server. Therefore, to get the time from the Internet, we must define the following three variables for NTP in the program.NTP_OFFSET
is the time zone of your country/region. For example, it is +5:30 in India so this time is 19800 seconds.NTP_INTERVAL
is the interval used by NTP to update the time, which is 60 ~ 64 seconds.NTP_ADDRESS
is the NTP server for your country. For instance, Indian users adopt “in.pool.ntp.org
”.
#define NTP_OFFSET 19800 // In seconds
#define NTP_INTERVAL 60 * 1000 // In miliseconds
#define NTP_ADDRESS "1.asia.pool.ntp.org"
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);
The setup() is used to initialize Wi-Fi Settings to connect to the Internet.
void setup(){
display.begin();
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
timeClient.begin();
Initialize the display to show the time on the OLED.
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
In
loop()
,timeClient.update()
gets the updated time from NTP as a string and stores it informattedTime
. Thendisplay.println()
is adopted.
void loop(){
timeClient.update();
String formattedTime = timeClient.getFormattedTime();
// Serial.println(formattedTime);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.println(formattedTime);
display.display(); // write the buffer to the display
delay(10);
delay(100);
}
1-2-19 Blynk-based Intrusion Notification System
1. Overview
In this project, we demonstrate a simple home intrusion alarm system with the PIR motion sensor. When we set it to “away mode” on the Blynk app, the PIR motion sensor monitors the motion. Any detected movement triggers a notification on the app, alerting the user to a potential intrusion.
2. Components
ESP32 main board x1 |
NPN transistor (S8050) x1 |
active buzzer x1 |
1kΩ resistor x1 |
PIR motion sensor x1 |
M-F DuPont wires |
red LED x1 |
220Ω resistor x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
10kΩ resistor x1 |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Blynk Configuration
4.1 Blynk Initialization
1. Turn to webpage:BLYNK and choose Sign Up Free(recommended) or Enterprise Solution.
2. Fill in your E-mail address to sign up an account.
3. Check your E-mail receiving. Click Create Password link in it to set a password for your account.
4. Input your name(or nickname) in “FIRST NAME” and click “Done”.
5. Now start your Blynk tour! First you will learn some basic functions of Blynk.
6. What’s next? You can choose “Explore Blueprints” or directly click “Quick Start” to connect to your device. But before that, please “Have a look around first”.
4.2 Template
1. Create a new template in Blynk and set “Intrusion Alert System”.
2. Name the new template and set the hardware to ESP32 and the “Connection Type” to WiFi. Click “Done”.
3. Click “Configure template” to upload its cover image and descriptions. The other three are similar. Actually, you can skip this step without setting them.
4.3 Datastreams
1. Click “(Datastreams)” to open the newly created template and go to “datastream setup”.
2. Click “New Datastream” to choose “Virtual Pin”.
3. Name the “Virtual Pin V0” to “AwayMode”, set the “DATA TYPE” to “Integer” whose MIN and MAX values are 0 and 1 respectively. Click “Create”.
4. Similarly, create a new “Virtual Pin” named “Current Status” and set the “DATA TYPE” to “String”.
4.4 Web Dashboard
1. Drag “Switch widget” and “Switch widget” into “Web Dashboard”.
2. Hover over the widget to see three ICONS. Set the properties of the widget in “(Settings)”.
3. Configure “Switch widget”; Link it to “AwayMode(V0)” data stream, and set “ONLABEL” and “OFFLABEL” to “away home” and “at home” respectively.
4. In “Label widget”, link it to “Current Status(V1)”.
4.5 Events
1. Click “(Events & Notifications)” to “Create Event”.
2. Name the new event and load its code. Set the “TYPE” to “Warning” and provide a short description of the notification email. Adjust notification frequency as needed. Note that make sure the “EVENT CODE” is set to intrusion_detected, because any changes here will require corresponding code adjustments.
3. In “Notifications”, enable notifications and set emails.
4. In “Settings”, define how often events trigger notifications and set the interval according to your preferences. Click “Create” to save your preference.
4.6 Save Template
1. Click “Save”.
4.7 Manufacturing Device
1. Create a new device.
2. Click “From template”.
3. Choose the template “Intrusion Alert System” and click “Create”.
4. Record the code collection of “Template ID”, “Device Name” and “AuthToken ESP32” for ESP32 which will be used in its code.
5. Test Code
Before uploading the code, you need to complete the following operations:
1. Replace the BLYNK_TEMPLATE_ID, BLYNK_TEMPLATE_NAME and BLYNK_AUTH_TOKEN in the code with your own unique ID. (You may copy the above “Template ID”, “Device Name” and “AuthToken ESP32”, and then replace the part circled in red below.)
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: Blynk-based_Intrusion_Notification_System
* Function: Intrusion notification system based on Blynk
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPxxxxxxx"
#define BLYNK_TEMPLATE_NAME "Intrusion Alert System"
#define BLYNK_AUTH_TOKEN "xxxxxxxxxxxxxxxx"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
// Define the PIR sensor pin and related variables
const int sensorPin = 14;
int state = 0;
int awayHomeMode = 0;
const int ledPin = 26; // Define LED pin to IO26.
const int buzzerPin = 19; // the buzzer pin
// Create Blynk Timer object
BlynkTimer timer;
void setup() {
Serial.begin(115200); // Start serial communication at 115200 baud rate for debugging
pinMode(sensorPin, INPUT); // Set PIR sensor pin as input
pinMode(ledPin, OUTPUT); // Set LED pin to output
pinMode(buzzerPin, OUTPUT); // Set as output
// Configure Blynk and connect to WiFi
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
timer.setInterval(1000L, myTimerEvent); // Setup a function to be called every second
}
void loop() {
Blynk.run(); // Run Blynk
timer.run(); // Run BlynkTimer
}
// This function is called every time the device is connected to the Blynk.Cloud
BLYNK_CONNECTED() {
Blynk.syncVirtual(V0);
}
// This function is called every time the Virtual Pin 0 state changes
BLYNK_WRITE(V0) {
awayHomeMode = param.asInt(); // Set incoming value from pin V0 to a variable
if (awayHomeMode == 1) {
Serial.println("The switch on Blynk has been turned on.");
Blynk.virtualWrite(V1, "Detecting signs of intrusion...");
} else {
Serial.println("The switch on Blynk has been turned off.");
Blynk.virtualWrite(V1, "Away home mode close");
}
}
void myTimerEvent() {
// Please don't send more that 10 values per second.
sendData(); // Call function to send sensor data to Blynk app
}
// Function to send sensor data to Blynk app
void sendData() {
if (awayHomeMode == 1) {
state = digitalRead(sensorPin); // Read the state of the PIR sensor
Serial.print("state:");
Serial.println(state);
// If the sensor detects movement, send an alert to the Blynk app
if (state == HIGH) {
Serial.println("Somebody here!");
Blynk.virtualWrite(V1, "Somebody in your house! Please check!");
Blynk.logEvent("intrusion_detected");
digitalWrite(ledPin, HIGH); // LED on.
digitalWrite(buzzerPin, HIGH); // Set to HIGH to make the buzzer sound
delay(500); // Delay 1s.
digitalWrite(ledPin, LOW); // LED off.
digitalWrite(buzzerPin, LOW); // LOW to turn off the buzzer
delay(500); // Delay 1s.
}
}
}
6. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-19 Blynk-based Intrusion Notification , open the file Blynk-based_Intrusion_Notification.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace BLYNK_TEMPLATE_ID, BLYNK_TEMPLATE_NAME, BLYNK_AUTH_TOKEN into your unique ID. And replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. After connecting to WiFi, activate the Blynk to enable the PIR motion sensor. When a motion is detected (state = 1), it says “Somebody here!” and you will receive a notification email. Meanwhise, the LED flashes and the buzzer alarms.
7. Code Explanation
1. Configuration and libraries. Here, you will set the Blynk constant and credentials. You also include the libraries required for ESP32 and Blynk.
/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPxxxxxxx"
#define BLYNK_TEMPLATE_NAME "Intrusion Alert System"
#define BLYNK_AUTH_TOKEN "xxxxxxxxxxxxxxxx"
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
2. WiFi Settings: input your WiFi name and passwords.
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
3. set IO pins of the PIR motion sensor, LED and buzzer, and initialize the state variables.
// Define the PIR sensor pin and related variables
const int sensorPin = 14;
int state = 0;
int awayHomeMode = 0;
const int ledPin = 26; // Define LED pin to IO26.
const int buzzerPin = 19; // the buzzer pin
4. setup() initializes PIR motion sensor to Input, LED and buzzer to Output. Set up serial communication, connect to WiFi and configure Blynk.
In
setup()
,timer.setInterval(1000L, myTimerEvent)
is used once. Here we makemyTimerEvent()
execute once every 1000ms. Or you can modify the first parameter ofsetInterval(1000L, myTimerEvent)
to change the execution interval of myTimerEvent.
void setup() {
Serial.begin(115200); // Start serial communication at 115200 baud rate for debugging
pinMode(sensorPin, INPUT); // Set PIR sensor pin as input
pinMode(ledPin, OUTPUT); // Set LED pin to output
pinMode(buzzerPin, OUTPUT); // Set as output
// Configure Blynk and connect to WiFi
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
timer.setInterval(1000L, myTimerEvent); // Setup a function to be called every second
}
5. loop()
always runs Blynk and Blynk counter function.
void loop() {
Blynk.run(); // Run Blynk
timer.run(); // Run BlynkTimer
}
6. Blynk application interaction. These functions are called when the device is connected to Blynk and when the state of the virtual pin V0 on the Blynk application changes.
Every time a device connects to a Blynk server, or reconnects due to poor network conditions,
BLYNK_CONNECTED()
will be called. Blynk.syncVirtual() acquires a Virtual Pin, and the specified Virtual Pin will callBLYNK_WRITE()
.When the virtual pin value on the BLYNK server changes,
BLYNK_WRITE()
will be called.
BLYNK_CONNECTED() {
Blynk.syncVirtual(V0);
}
// This function is called every time the Virtual Pin 0 state changes
BLYNK_WRITE(V0) {
awayHomeMode = param.asInt(); // Set incoming value from pin V0 to a variable
}
7. Data processing. myTimerEvent()
calls sendData()
per second. If Away mode is enabled on Blynk, it checks the PIR motion sensor and sends a notification to Blynk when motion is detected.
Blynk.virtualWrite(V1, "Somebody in your house! Please check!");
changes the text of the label.Blynk.logEvent("intrusion_detected");
records the event to Blynk.
void myTimerEvent() {
// Please don't send more that 10 values per second.
sendData(); // Call function to send sensor data to Blynk app
}
// Function to send sensor data to Blynk app
void sendData() {
if (awayHomeMode == 1) {
state = digitalRead(sensorPin); // Read the state of the PIR sensor
Serial.print("state:");
Serial.println(state);
// If the sensor detects movement, send an alert to the Blynk app
if (state == HIGH) {
Serial.println("Somebody here!");
Blynk.virtualWrite(V1, "Somebody in your house! Please check!");
Blynk.logEvent("intrusion_detected");
digitalWrite(ledPin, HIGH); // LED on.
digitalWrite(buzzerPin, HIGH); // Set to HIGH to make the buzzer sound
delay(500); // Delay 1s.
digitalWrite(ledPin, LOW); // LED off.
digitalWrite(buzzerPin, LOW); // LOW to turn off the buzzer
delay(500); // Delay 1s.
}
}
}
1-2-20 WiFi Web Control Smart Life
1. Overview
In previous experiments, we have understood the WiFi + ESP32 Web function of the ESP32 module. Herein, we control multiple modules on a web pages through the ESP32 WiFi.
2. Components
ESP32 main board x1 |
S8050 transistor x1 |
servo ×1 |
1kΩ resistor x1 |
DC motor x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
fan x1 |
battery holder x1 |
AA battery (self-provided) x6 |
10kΩ resistor x1 |
mobile device x1 |
RGB LED x1 |
relay x1 |
LED x1 |
active buzzer ×1 |
220Ω resistor ×4 |
F-F DuPont wires |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
⚠️ATTENTION: After wiring up, mount the fan on the motor.
4. Test Code
⚠️ATTENTION: Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
/*
* Filename: WiFi_Web_Control_Smart_Life
* Function: WIFI web controls multiple components and modules to simulate WiFi smart life
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <Arduino.h>
#include <WiFi.h>
#include <ESP32Servo.h>
/*REPLACE WITH YOUR NETWORK CREDENTIALS(Put your SSID & Password)*/
const char* ssid = "REPLACE_WITH_YOUR_SSID"; //Enter SSID here
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; //Enter Password here
// A variable used to store HTTP requests
String header;
const int ledPins[] = {27, 16, 17}; // Define the red, green, and blue pins in order
const byte chns[] = {1, 2, 3}; // Define PWM channel
int red, green, blue;
const int buzzerPin = 18; // set active buzzer pin to IO18
const int motoraPin = 13; // set motor IN+ digital pin to IO13
const int motorbPin = 12; // set motor IN- digital pin to IO12
const int relayPin = 25; // set relay pin to IO25
const int servoPin = 4; // set servo pin to IO4
Servo myservo; // Create servo objects to control servo
// Define the minimum and maximum pulse widths for the servo
const int minPulseWidth = 500; // 0.5 ms
const int maxPulseWidth = 2500; // 2.5 ms
int status = WL_IDLE_STATUS;
WiFiServer server(80);
unsigned long currentTime = millis(); // Current time
unsigned long previousTime = 0; // Previous time
const long timeoutTime = 2000; // set timeout period in milliseconds (example: 2000ms = 2s)
void setup() {
Serial.begin(115200); // set baud rate
for (int i = 0; i < 3; i++) { //set pwm channel,1KHz,8bit
ledcSetup(chns[i], 1000, 8);
ledcAttachPin(ledPins[i], chns[i]);
}
pinMode(motoraPin, OUTPUT); // set motor 的IN+ pin to output
pinMode(motorbPin, OUTPUT); // set motor 的IN- pin to output
pinMode(relayPin, OUTPUT); // set relay pin to output
pinMode(buzzerPin, OUTPUT); // set active buzzer pin to output
myservo.attach(servoPin); //set servo pin to IO4
myservo.write(0); //rotate to 0°
delay(1000); //delay 1s
// Connect to a Wi-Fi network through the SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print the local IP address and start the Web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
WiFiClient client = server.available(); // Monitor data
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // Print a message in the serial monitor
String currentLine = ""; // Create a string to store incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // Loop when the client connects
currentTime = millis();
if (client.available()) { // If there are bytes to be read from the client,
char c = client.read(); // Read a byte
Serial.write(c); // Print it out to the serial monitor
header += c;
if (c == '\n') { // If the byte is a line-break
// If the current line is empty, there are two newlines in a row.
// This is the end of the client HTTP request, so send the response:
if (currentLine.length() == 0) {
// HTTP header always starts with a response code (e.g. HTTP/1.1 200 OK)
// A content type so that the client knows what to expect next, followed by a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// web page title
client.println("<body><h1>ESP32 Web Server</h1>");
// The content of the HTTP response follows the header:
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/A\">here</a> turn on Relay<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/B\">here</a> turn off Relay<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/C\">here</a> turn on RGB<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/D\">here</a> turn off RGB<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/E\">here</a> turn on fan<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/F\">here</a> turn off fan<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/G\">here</a> turn on buzzer<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/H\">here</a> turn off buzzer<br></p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/I\">here</a> <br>servo turn to 180</p>");
client.print("<p style=\"font-size:7vw;\">Click <a href=\"/J\">here</a> <br>servo turn to 0</p>");
// The HTTP response ends with another blank line:
client.println();
// exit while loop:
break;
} else { // If line break, clear currentLine:
currentLine = "";
}
} else if (c != '\r') { // If there are any characters other than the carriage return,
currentLine += c; // And add it to the end of currentLine
}
// Check whether the client request exists "GET /A"or"GET /B"or"GET /C"or"GET /D"or"GET /E"or"GET /F"or"GET /G"or"GET /H"or"GET /I"or"GET /J":
if (currentLine.endsWith("GET /A")) { // GET /A turn off relay
digitalWrite(relayPin, HIGH);
}
if (currentLine.endsWith("GET /B")) { // GET /B turn off relay
digitalWrite(relayPin, LOW);
}
if (currentLine.endsWith("GET /C")) { // GET /C turn off RGB
// Cycle through basic colors
setColor(255, 0, 0); // Red
delay(1000); // Wait for 1 second
setColor(0, 255, 0); // Green
delay(1000); // Wait for 1 second
setColor(0, 0, 255); // Blue
delay(1000); // Wait for 1 second
// Cycle through blended colors
setColor(255, 0, 252); // Magenta
delay(1000); // Wait for 1 second
setColor(237, 109, 0); // Orange
delay(1000); // Wait for 1 second
setColor(255, 215, 0); // Yellow
delay(1000); // Wait for 1 second
setColor(34, 139, 34); // Forest Green
delay(1000); // Wait for 1 second
setColor(0, 112, 255); // Light Blue
delay(1000); // Wait for 1 second
setColor(0, 46, 90); // Indigo
delay(1000); // Wait for 1 second
setColor(128, 0, 128); // Purple
delay(1000); // Wait for 1 second
}
if (currentLine.endsWith("GET /D")) { // GET /D turn off RGB
setColor(0, 0, 0); // Black
}
if (currentLine.endsWith("GET /E")) { // GET /E motor rotate
digitalWrite(motoraPin, LOW);
digitalWrite(motorbPin, HIGH);
}
if (currentLine.endsWith("GET /F")) { // GET /F motor does not rotate
digitalWrite(motoraPin, LOW);
digitalWrite(motorbPin, LOW);
}
if (currentLine.endsWith("GET /G")) { // GET /G turn off active buzzer
digitalWrite(buzzerPin, HIGH);
}
if (currentLine.endsWith("GET /H")) { // GET /H turn off passive buzzer
digitalWrite(buzzerPin, LOW);
}
if (currentLine.endsWith("GET /I")) { // GET /J servorotates to 180°
myservo.write(180); //rotate to 180°
delay(1000); //delay 1s
}
if (currentLine.endsWith("GET /J")) { // GET /K servorotates to 0°
myservo.write(0); //rotate to 0°
delay(1000); //delay 1s
}
}
}
// clear header
header = "";
// disconnect:
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
// Function to set the RGB LED color
void setColor(int red, int green, int blue) {
ledcWrite(chns[1], red); //Common cathode LED, is on at high level
ledcWrite(chns[2], green);
ledcWrite(chns[3], blue);
}
5. Test Result
Please follow the steps below:
1. In folder …\Codes\Arduino_C_Code\1-2-IoT_C_Code\1-2-20 WiFi Web Control Smart Life , open the file WiFi_Web_Control_Smart_Life.ino , or copy and paste the above test code into the Arduino IDE.
2. Before uploading code, please replace the WiFi name(REPLACE_WITH_YOUR_SSID) in the code and the passwords(REPLACE_WITH_YOUR_PASSWORD) into yours.
⚠️ATTENTION: Make sure that the WiFi name and passwords in the code is the same as the network connected to your computer, phone/tablet, ESP32 board, and the router. They must be under the same local area network (WiFi).
3. Check whether the required library(s) is(are) installed. If not, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
4. Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code.
5. After uploading code, open the serial monitor and set the baud rate to 115200. The corresponding IP address will be displayed on the monitor.
⚠️Note that if there is no IP address on the monitor, please press the RESET button on the ESP32 board.
6. Open the browser on your phone and input the WIFI IP address in it and “search”.
7. After a few seconds, enter the WiFi web page, indicating that the ESP32 module is successfully connected to WiFi. The WiFi web page displays the following content.
Button |
Click |
Function |
---|---|---|
Click here |
relay close, LED on |
|
Click here |
relay open, LED off |
|
Click here |
RGB LED on, RGB LED in different colors |
|
Click here |
RGB LED off |
|
Click here |
DC motor on, fan rotates |
|
Click here |
DC motor off, fan off |
|
Click here |
active buzzer beeps |
|
Click here |
active buzzer off |
|
Click here |
servo rotates to 180° |
|
Click here |
servo rotates to 0° |
6. Code Explanation
Please refer to the previous Code Explanation.
1-3 Basic Projects
Herein, we do experiments with ESP32 main board, breadboard and sensors/modules. After connecting a sensor to the main board and uploading code, the function of each sensor can be tested. Besides, the working principles of modules are also included in each project so that we can have a deep understanding of each component.
⚠️ATTENTION: During experiment, please connect to pins and power supply according to the wiring diagrams, or else the sensor/module may be damaged.
1-3-01 Hello, LED!
1. Overview
LED: Its full name is light-emitting diode made of compounds containing gallium (Ga), arsenic (As), phosphorus (P), nitrogen (N), etc. When electrons are combined with holes, visible light is emitted. So they can be used to produce light-emitting diodes. Except by components, they can also be divided into organic ones(OLED) and inorganic ones(LED).
LED components |
Emitting light colors |
---|---|
gallium arsenide diode |
red |
gallium phosphide diode |
green |
silicon carbide diode |
yellow |
gallium nitride diode |
blue |
LED is used as an indicator in circuits and instruments, or as part of a text or numeric display. In this project, we connect an external LED to digital pin IO26.
2. Component Knowledge
(1) LED
An LED is a semiconductor known as a “light-emitting diode”, which is made of semiconductor materials (silicon, selenium, germanium, etc.). It is polar. The short pin is negative that connects to GND, while the long one is positive that connects to 3.3V or 5V.
Here is the detailed introduction for the LED: LED - Wikipedia
(2) Five-color-ring Resistor
A resistor limits or regulates the flow of current in the circuit. The left picture is the appearance of the resistor and the right one is its circuit symbol. Its unit of R is ohm(Ω). 1 MΩ= 1000 kΩ, 1 kΩ = 1000Ω.
We can use resistors to protect sensitive components, like LED. The resistance(Ω) is marked on the body with an electronic color code. Each color represents a number, and you can refer to it in the resistance card.
-ring 1 – 1st Digit. -ring 2 – 2nd Digit. -ring 3 – 3rd Digit. -ring 4 – Multiplier. -ring 5 – Tolerance.
In this kit, we provide four five-color-ring resistor. Here we take three of them as examples.
220Ω resistor *10
10KΩ resistor *10
1KΩ resistor *10
You can learn more about resistor from Wiki: Resistor - Wikipedia
In the same voltage, there will be less current but more resistance. The connection between current(I), voltage(V), and resistance® can be expressed: I=U/R. In the figure below, for instance, if the voltage is 3V, the current through R1 equals I = U / R = 3 V / 10 KΩ= 0.0003A= 0.3mA.
You can learn more about Ohm’s Law from Wiki: Ohm’s Law - Wikipedia
Don’t connect a low resistance directly to the two poles of the power supply, as this will cause excessive current to damage the electronic components. Resistors are nonpolar.
(3) Breadboard
Breadboards are used to build and test circuits quickly before completing any circuit design. There are many holes in the breadboard so that components such as resistors can be inserted into it.
A typical breadboard is shown below:
The breadboard comes with many metal strips that run underneath the board to connect holes together. They are laid out as shown below. Note that the top and bottom rows of holes are connected horizontally, while the remaining holes are connected vertically.
The first two rows (top) and the last two rows (bottom) are used for power positive(+) and negative(-) respectively. The conductive layout is shown below:
We should know that the up and low holes of groove in the middle are not connected. So we can connect the DIP(Dual in-line Packages) components (say, integrated circuits, microcontrollers, chips, etc.) as shown below:
If you want to know more about breadboard, refer to: How to Use a Breadboard - Science Buddies
3. Components
ESP32 main board x1 |
red LED x1 |
220Ω resistor x1 |
mobile device x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
4. Wiring Diagram
We adopt digital pin IO26 in this experiment. In the circuit, we connect a 220Ω resistor in serial, which protect the LED from over-current.
Schematic diagram:
Wiring diagram:
5. Test Code
/*
* File name: Hello,LED
* Function: LED blinks 1s
* Compiling IDE: ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int ledPin = 26; // Define LED pin to IO26.
void setup(){
pinMode(ledPin, OUTPUT); // Set LED pin to output
}
void loop(){
digitalWrite(ledPin, HIGH); // LED on.
delay(1000); // Delay 1s.
digitalWrite(ledPin, LOW); // LED off.
delay(1000); // Delay 1s.
}
Connect the ESP32 main board to your computer via Micro USB cable.
Click “Tools” → “Board” to choose ESP32 Dev Module and serial port COMxx.
⚠️Note that the port will appear only after the board is connected to computer via USB cable.
Click to upload the code to the board.
Code uploaded.
6. Test Result
After uploading the code, unplug the USB cable and wire up. Connect the board to the computer with USB cable and you will see the red LED blinks: it lights up for 1s and goes off for 1s, in a loop.
7. Code Explanation
1. Declare a variable named ledPin and assign it the digital pin IO26.
const int ledPin = 26; // Define LED pin to IO26.
2. In setup()
, initialize the pin to OUTPUT mode.
void setup(){
pinMode(ledPin, OUTPUT); // Set LED pin to output
}
void pinMode(uint8_t pin, uint8_t mode);
: This function is used to define a specific GPIO pin operation mode.pin
defines the GPIO pin number.mode
sets the operation mode.
Basic input and output support the following modes:
INPUT
sets the GPIO to none-pullup or pulldown (high impedance) input.OUTPUT
sets GPIO to output/read mode.INPUT_PULLDOWN
sets GPIO to an input with an internal Pulldown.INPUT_PULLUP
sets GPIO to input with an internal pull-up.
3. loop()
includes the program’s main logic and runs continuously. It alternates between high and low for one second intervals.
void loop(){
digitalWrite(ledPin, HIGH); // LED on.
delay(1000); // Delay 1s.
digitalWrite(ledPin, LOW); // LED off.
delay(1000); // Delay 1s.
}
1-3-02 Breathing LED
1. Overview
In previous studies, we control LED on/off state through digital output. Herein, we adopt PWM to light and dim the LED gradually. PWM is a technology that allows us to control the brightness of an LED or the speed of a motor by changing the duty cycle of a square-wave signal.
With PWM, instead of simply turning the LED on or off, we adjust the time the LED lights up and the time it turns off within each cycle, so that the LED will “breathe” evenly.
This breathing lighting adds a dynamic effect, attracting eyes.
2. Working Principle
Analog / Digital signal
An Analog Signal is a continuous signal in both time and value. On the contrary, a Digital Signal is a time series consisting of a sequence of quantities. Most signals in life are analog signals. A familiar example of an Analog Signal would be how the temperature throughout the day is continuously changing and could not suddenly change instantaneously from 0℃ to 10℃. However, Digital Signals can instantaneously change in value. This change is expressed in numbers as 1 and 0 (binary). Their differences can more easily be seen when compared when graphed as below.
PWM:
Pulse Width Modulation, is a very effective method for using digital signals to control analog circuits. Common processors cannot directly output analog signals. PWM technology makes it very convenient to achieve this conversion (translation from digital to analog signals).
PWM technology uses digital pins to send certain frequencies of square waves, that is, the output of high levels and low levels, which alternately last for a certain period. The total time is generally fixed, which is called the period (the reciprocal of the period is frequency). The time of high level outputs are generally called “pulse width”, and the duty cycle is the percentage of the ratio of pulse duration, or pulse width (PW) to the total period (T) of the waveform. The longer the high levels last, the longer the duty cycle and the higher the corresponding voltage in the analog signal will be.
The following figures show how the analog signal voltages vary between 0V-3.3V (high level is 3.3V) corresponding to the pulse width 0%-100%.
PWM is widely applied to adjust light brightness, motor rotation speed and sound production. Here are three parameters of it.
1. Duty cycle: The duration proportion of high level to the total period
2. Period: The reciprocal of the pulse frequency in one second
3. On the ESP32, the LEDC(PWM) controller comes with 16 independent channels, each of which can independently control frequency, duty cycle and accuracy.
The longer the PWM duty cycle is, the higher the output power will be. So we can use PWM to control the brightness of an LED or the speed of DC motor. PWM is not real analog, but the effective value of the voltage is equivalent to the corresponding analog. Therefore, we can control the output power of modules.
ESP32 and PWM
On the ESP32, the LEDC(PWM) controller boasts 16 independent channels, each of which can independently control frequency, duty cycle, and even accuracy. Unlike traditional PWM pins, the ESP32’s PWM output pins are configurable, with one or more PWM output pins per channel. The relationship between maximum frequency and bit accuracy is shown below:
The maximum of bits is 31. For example, generate PWM with 8-bit precision (2ˆ8 = 256, ranging from 0 to 255), and the maximum frequency is 80,000,000/255 = 312,500Hz).
3. Components
ESP32 main board x1 |
red LED x1 |
220Ω resistor x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
4. Wiring Diagram
Here we use digital pin IO26. We connect the LED to a 220Ω resistor to avoid high current damage to the LED.
Schematic diagram:
The pin in this experiment is the same as “1-3-1 Hello, LED!” but the signal type is not. In the last project, IO26 outputs digital high/low levels (0 & 1) to turn on/off LED, while here IO26 outputs PWM signals to adjust the brightness of the LED.
Wiring diagram:
5. Test Code
/*
* Filename: Breathing_LED
* Function: Make led light fade in and out, just like breathing.
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int ledPin = 26; // The GPIO pin for the LED
int CHN = 0; // define the pwm channel
int FRQ = 1000; // define the pwm frequency
int PWM_BIT = 8; // define the pwm resolution for ledc channel
void setup() {
ledcSetup(CHN, FRQ, PWM_BIT); // setup pwm channel,frequency and resolution for ledc channel.
ledcAttachPin(ledPin, CHN); // attach the led pin to pwm channel
}
void loop() {
for (int i = 0; i < 255; i++) { //make light fade in
ledcWrite(CHN, i);
delay(5);
}
for (int i = 255; i > -1; i--) { //make light fade out
ledcWrite(CHN, i);
delay(5);
}
}
Connect the ESP32 main board to your computer via Micro USB cable.
Click “Tools” → “Board” to choose ESP32 Dev Module and serial port COMxx.
⚠️Note that the port will appear only after the board is connected to computer via USB cable.
Click to upload the code to the board.
Code uploaded.
6. Test Result
After uploading the code, unplug the USB cable and wire up. Connect the board to the computer with USB cable. The LED gradually turns on and off, just like breathing.
7. Code Explanation
1. set pins, constants and variables.
const int ledPin = 26; // The GPIO pin for the LED
int CHN = 0; // define the pwm channel
int FRQ = 1000; // define the pwm frequency
int PWM_BIT = 8; // define the pwm frequency
ledPin: The GPIO pin number that connects the LED (here is GPIO 26).
CHN: LED Current PWM channel number.
FRQ: Current PWM frequency of LED.
PWM_BIT: The resolution of the PWM channel; ranging from 1-14 bits (1-20 bits for the ESP32).
2. Initialize the PWM channel and configure the pins of the PWM output specified by the LED.
void setup() {
ledcSetup(CHN, FRQ, PWM_BIT); // setup pwm channel
ledcAttachPin(ledPin, CHN); // attach the led pin to pwm channel
}
Here, we use the LEDC (LED Control) peripheral, which is used to generate PWM signals.
ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num);
: It is used to set the LEDC pin for the specified channel number, PWM frequency and resolution. The PWM channel is automatically selected.chan
: Channel number to be configured; ranging from 0 to 15. An LED controller can connect multiple channels, each of which can control an LED independently.freq
: The PWM frequency(Hz) of the configured channel. PWM (Pulse Width modulation) is used to generate analog signals and control the brightness of LED.bit_num
: The number of bits(resolution) representing the channel to be configured. This parameter determines the accuracy of the PWM signal, i.e. how many different levels of brightness can be generated. Higher bits lead to more precise control but may require more computing and storage resources. The range is 1-14 bits (1-20 bits for ESP32).
ledcAttachPin(uint8_t pin, uint8_t chan);
: It specifies the pin and channel numbers for the PWM output. Parameter 1 is the output to which pin, and parameter 2 is the pwm channel and must be the same as the ledcSetup channel.
3. loop()
includes the program’s main logic and runs continuously. It updates and changes the brightness of the LED when the it reaches a minimum or maximum. A delay follows.
void loop() {
for (int i = 0; i < 255; i++) { //make light fade in
ledcWrite(CHN, i);
delay(5);
}
for (int i = 255; i > -1; i--) { //make light fade out
ledcWrite(CHN, i);
delay(5);
}
}
When we need to repeat something, we can use the for statement.
for loop:
The first loop: 1 → 2 → 3 → 4
The second loop: 2 → 3 → 4
…
The loop ends until 2 is not satisfied.
Back to the code:
for (int i = 0; i < 255; i++){
...}
for (int i = 255; i > -1; i--){
...}
The value of i increases from 0 to 255 and decreases to 0, and then it back to 255…
In the for loop, there is a new function ledcWrite().
We know that the digital port only has two states of 0 and 1, so how to send an analog value to a digital pin? This function is going to be used. On the ESP32 main board, digital pins: IO13, IO12, IO14, IO27, IO26, IO25, IO33, IO32, IO16, IO17, IO0, IO4, IO5, IO18, IO19, IO21, IO22, IO23, are different from other pins in that they can output PWM signals.
ledcWrite(CHN, i);
ledcWrite() is used to write an analog value ranging from 0 to 255 to the LEDC channel. So, i is a value between 0 and 255. In particular, the ledcWrite() function can only write digital pins that have LEDC channels, i.e., IO13, IO12, IO14, IO27, IO26, IO25, IO33, IO32, IO16, IO17, IO0, IO4, IO5, IO18, IO19, IO21, IO22, IO23 pins.
1-3-03 Traffic Lights
1. Overview
Traffic lights are closely related to people’s daily life, which generally show red, yellow, and green. Everyone should obey the traffic rules to avoid many accidents.
In this project, we will adopt red, green and yellow LED to make a mini traffic lights.
2. Components
ESP32 main board x1 |
red LED x1 |
green LED x1 |
yellow LED x1 |
220Ω resistor x3 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Test Code
/*
* Filename: Traffic_Lights
* Function: traffic lights
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int PIN_LED_RED = 13; //define red LED pin
const int PIN_LED_YELLOW = 14; //define yellow LED pin
const int PIN_LED_GREEN = 16; //define green LED pin
void setup() {
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_YELLOW, OUTPUT);
pinMode(PIN_LED_GREEN, OUTPUT);
}
void loop() {
digitalWrite(PIN_LED_GREEN, HIGH);// turn on green LED
delay(5000);// Delay 5 s
digitalWrite(PIN_LED_GREEN, LOW);//
delay(500);// Delay 0.5 s
for(int i=0;i<3;i++)// Blink 3 times
{
digitalWrite(PIN_LED_YELLOW, HIGH);// Turn on yellow LED
delay(500);// Delay 0.5 s
digitalWrite(PIN_LED_YELLOW, LOW);// Turn off yellow LED
delay(500);// Delay 0.5 s
}
digitalWrite(PIN_LED_RED, HIGH);// Turn on red LED
delay(5000);// Delay 5 s
digitalWrite(PIN_LED_RED, LOW); // Turn off red LED
delay(500);// Delay 0.5 s
}
5. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The green LED lights up for 5 seconds and goes off; then the yellow LED blinks for three times; at last the red LED also lights up for 5 seconds and goes off. These actions repeat.
6. Code Explanation
1-3-04 Flowing Water Light
1. Overview
In our daily life, we can see many billboards composed of different colors of LED. They constantly change the light (like water) to attract customers’ attention. In this project, we will use ESP32 main board to control 5 LEDs to achieve the effect of flowing water.
2. Components
ESP32 main board x1 |
red LED x5 |
220Ω resistor x5 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
3. Wiring Diagram
Schematic diagram:
Wiring diagram:
4. Test Code
This project is to design a water flow LED. It first turn on LED #1 and off; Then turn on LED #2 and off… And repeat the same operation for all 5 leds until the last LED is turned off. This just likes the “movement” of the water.
/*
* Filename: Flowing_Water_Light
* Function: Flowing water light
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
byte ledPins[] = {18, 5, 14, 17, 26}; //set LED pins
int ledCounts; //define the number of LED
void setup() {
//Set 5 LEDs to output mode
ledCounts = sizeof(ledPins);
for (int i = 0; i < ledCounts; i++) {
pinMode(ledPins[i], OUTPUT);
}
}
void loop() {
for (int i = 0; i < ledCounts; i++) { //The five leds will turn on and off from right to left
digitalWrite(ledPins[i], HIGH);
delay(100);
digitalWrite(ledPins[i], LOW);
}
for (int i = ledCounts - 1; i > -1; i--) { //The five leds will turn on and off from left to right
digitalWrite(ledPins[i], HIGH);
delay(100);
digitalWrite(ledPins[i], LOW);
}
}
5. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, unplug the USB cable and wire up. Connect the board to the computer with USB cable. These LEDs gradually light up and go off in sequence.
6. Code Explanation
1. Set the pins and the number of LED.
byte ledPins[] = {18, 5, 14, 17, 26}; //LED pins
int ledCounts; //the number of LED
2. a is an array of 9 bits int, sizeof(a) is the total number of bytes stored in a, which is 9*4=36.
sizeof(a);
For others, please refer to Project 1-3-01 and 1-3-02 Code Explanation.
1-3-05 RGB LED
1. Overview
RGB LED combines three primary color (red, green and blue) pins that share a common cathode and whose anode pins control the intensity of the corresponding color. By varying the strength of the electrical signal applied to each anode, it produces a wide variety of colors. For example, mix high-intensity red and green to show yellow, while blue and green to cyan.
In this project, we will introduce the principles of additive color mixing and display colors with RGB LED.
2. Component Knowledge
RGB LED (red, green, and blue) are packaged in a transparent/translucent plastic housing. It can display a variety of colors by changing the input voltage of the three pins, which can statistically produce 16,777,216 different colors.
Features:
Color: Three colors (Red/Green/blue)
Common cathode
5mm transparent round lens
Forward voltage: Red: DC 2.0-2.2V; Blue Green: DC 3.0-3.2V (IF=20mA)
0.06 watt DIP RGB LED
Brightness up to + 20%
Viewing Angle: 30°
Common anode and common cathode:
For common cathode RGB LED, three pins share a negative connection (cathode).
For common anode RGB LED, three pins share a positive connection (anode).
In this kit, the RGB LED is a common cathode one.
RGB LED pins:
There are 4 pins: the longest is GND; The others are red, green and blue. Place the RGB led as shown, the second from the left being the longest pin. So the pin numbers should be red, GND, green and blue.
You can also use the multimeter “diode” test mode to press the connection as shown to measure the color of each pin.
Mixed color:
Three colors can be combined in different intensities to generate additional colors, and intensities can be controlled by PWM.
Because they are so close to each other, so our eyes see the result of a combination rather than colors alone.
Take a look at the image below and you may understand how different colors are produced.
Here is the detailed introduction for a dditive color of the RGB: Additive color - Wikipedia
The brightness of RGB LED can be adjusted by PWM.
3. Components
ESP32 main board x1 |
RGB LED x1 |
220Ω resistor x3 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
Here, we can choose our favorite color in the drawing software and display it with RGB LED.
/*
* Filename: RGB_LED
* Function: RGB LED shines in different colors
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int ledPins[] = {27, 25, 26}; //Define the red, green, and blue pins
const byte chns[] = {0, 1, 2}; //define PWM channel
int red, green, blue;
void setup() {
for (int i = 0; i < 3; i++) { //Set pwm channel, 1KHz, 8bit
ledcSetup(chns[i], 1000, 8);
ledcAttachPin(ledPins[i], chns[i]);
}
}
void loop() {
setColor(255, 0, 0); // Red
delay(1000);
setColor(0, 255, 0); // Green
delay(1000);
setColor(0, 0, 255); // Blue
delay(1000);
setColor(255, 255, 0); // Yellow
delay(1000);
setColor(80, 0, 80); // Purple
delay(1000);
setColor(0, 255, 255); // Cyan
delay(1000);
}
void setColor(int red, int green, int blue) {
ledcWrite(chns[0], red); //Common cathode LED, high level on
ledcWrite(chns[1], green);
ledcWrite(chns[2], blue);
}
Write the RGB value to setColor() and you will be able to see RGB light up the color you want.
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. RGB LED shows the colors you set.
7. Code Explanation
1. Set GPIO pins and PWM channels.
const int ledPins[] = {27, 25, 26}; // Define the red, green, and blue pins
const byte chns[] = {0, 1, 2}; // Defining PWM channel
int red, green, blue;
2. setup() initializes the PWM channel at the specified frequency and resolution, and then connects the LED pins to the corresponding PWM channel along with the frequency (in Hz) and resolution (in bits).
void setup() {
for (int i = 0; i < 3; i++) { // set pwm channel, 1KHz, 8bit
ledcSetup(chns[i], 1000, 8);
ledcAttachPin(ledPins[i], chns[i]);
}
}
Herein, we use the LEDC (LED Control) peripheral, which was originally designed to control the strength of the LED, although it can also be used to generate PWM signals.
ledcSetup(CHN, uint32_t freq, uint8_t resolution); ledcAttachPin(uint8_t pin, CHN);
It is used to set the LEDC pin for a given frequency and resolution. The LEDC channel is automatically selected.
freq
selects Frequency of PWM (the frequency of PWM).resolution_bits
selects LEDC channel resolution. Range 1-14 bits (1-20 bits for ESP32)
3. loop() loops through various colors (red, green, blue, yellow, purple, and cyan) with a one-second interval between each color change.
void loop() {
setColor(255, 0, 0); // Red
delay(1000);
setColor(0, 255, 0); // Green
delay(1000);
setColor(0, 0, 255); // Blue
delay(1000);
setColor(255, 255, 0); // Yellow
delay(1000);
setColor(80, 0, 80); // Purple
delay(1000);
setColor(0, 255, 255); // Cyan
delay(1000);
}
4. setColor()
sets the desired color by writing the appropriate duty cycle to each PWM channel. It accepts three integer parameters representing the color values of red, green, and blue.
void setColor(int red, int green, int blue) {
ledcWrite(chns[0], red); //Common cathode LED, high level LED on.
ledcWrite(chns[1], green);
ledcWrite(chns[2], blue);
}
1-3-06 74HC595N
1. Overview
The 74HC595 chip can be used to control 8 outputs at once, taking up only a few pins on microcontroller. In addition, multiple registers can connects to each other for further output expansion.
In this project, we will use 74HC595 chip to turn on/off 8 LEDs. They just like a rainbow shining colorful lights.
2. Component Knowledge
Have you ever found yourself wanting to control a lot of leds, or just needing more I/O pins to control buttons, sensors, and servos? Well, you can connect some sensors to the Arduino pins, but you’ll run out of Arduino pins pretty quickly.
The solution is to use “shift registers” that allows you to expand the number of I/O pins from the Arduino (or any microcontroller). The 74HC595 shift register is one of the most famous.
The 74HC595 essentially controls eight separate output pins, using only three input pins. If you need more than 8 additional I/O lines, you can easily cascade any number of shift registers and create a large number of I/O lines. All of this is done through what’s called a shift register.
Features:
8-bit serial input, parallel output shift;
Operating voltage range 2V to 6V;
High current tri-state output can drive up to 15LSTTL loads;
Low power consumption, 80µA Max ICC;
Typical tPD = 14 ns;
±6ma output drive at 5v;
Low input current, Max. 1µA;
The shift register has a direct clear function.
74HC595 pins and function:
Q0-Q7: 8-bit parallel data output pins for direct control of 8 leds or 8 7-segment display pins.
SQR: Series output pin, connecting another 74HC595 DS, series multiple 74HC595
SCLR: Reset pin, enable at low level;
SCK: Timing input of the shift register. On the rising edge, the data in the shift register is continuously moved 1 bit, that is, the data from Q1 is moved to Q2, and so on. At the falling edge, the data in the shift register remains unchanged.
RCK: Stores the timing input of the register. At the rising edge, the data in the shift register is moved to the memory register.
OE: Output enable pin, enable at low level.
SI: serial data entry pin
VCC: positive voltage of the power supply.
GND: Ground.
Function diagram:
Working Principle
When SCLR (pin10) is high and OE (pin13) is low, data is entered from the rising edge of SCK and into the memory register via the rising edge of RCK.
Shift register
Suppose we want to input binary data 1110 1110 into the 74hc595 shift register.
Data is input from the 0 bit of the shift register.
Each time the shift register clock is on a rising edge, the bits in the shift register are shifted by one step. For example, the 7th bit accepts the value before the 6th, the 6th obtains the value of the 5th, and so on.
Memory register
When the storage register is in the rising edge state, the data in the shift register will be transferred to the storage register.
Connect the memory register directly to the eight output pins, and Q0 to Q7 can receive one byte of data.
The so-called storage register means that data can exist in this register and will not disappear with an output.
As long as the 74HC595 is powered on, the data will remain valid and unchanged.
When new data appears, the data in the storage register will be overwritten and updated.
3. Components
ESP32 main board x1 |
74HC595N x1 |
red LED x8 |
220Ω resistor x8 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
When SCLR (pin10) is at a high level and OE (pin13) is at a low level, data is input from the rising edge of SCK and enters the memory register through the rising edge of SCK.
If two clocks are connected together, the shift register is always one pulse ahead of the memory register.
In the memory register there is a serial shift input pin (SI), a serial output pin (SQH), and an asynchronous reset button (low level).
The memory register outputs a bus with parallel 8-bits and three states.
When OE is enabled (low level), the data in the memory register is output to the bus (Q0 ~ Q7).
Wiring diagram:
Pay attention to the insert direction of the 74HC595N
5. Test Code
/*
* Filename: 74HC595N
* Function: 74HC595N control 8 LEDs to form water flowing LED
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int rckPin = 23; //RCK
const int sckPin = 18; //SCK
const int siPin = 5; //SI
int datArray[] = {B00000000, B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111};
void setup (){
//set pins to output
pinMode(rckPin,OUTPUT);
pinMode(sckPin,OUTPUT);
pinMode(siPin,OUTPUT);
}
void loop(){
for(int num = 0; num < 9; num++){
digitalWrite(rckPin,LOW); //ground RCK and hold low for as long as you are transmitting
shiftOut(siPin,sckPin,MSBFIRST,datArray[num]);
digitalWrite(rckPin,HIGH); //pull the RCK to save the data
delay(1000);
}
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. LEDs in the circuit turn on and off one by one.
7. Code Explanation
1. Declare an array that stores several 8-bit binary numbers for changing the operating state of the 8 leds controlled by 74HC595.
int datArray[] = {B00000000, B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111};
2. loop()
void loop(){
for(int num = 0; num <10; num++){
digitalWrite(RCK,LOW); //Set RCK and hold low for as long as you are transmitting
shiftOut(SI,SCK,MSBFIRST,datArray[num]);
digitalWrite(RCK,HIGH); //pull the RCK to save the data
delay(1000);
}
}
With
datArray[]
, the binary values are successively sent to the shift register.digitalWrite(RCK,LOW)
anddigitalWrite(RCK,HIGH)
commands latch the data to a storage register.shiftOut()
uses the data pin (SI) and the shift register clock pin (SCK) to send binary values from the datArray[] to the shift register. MSBFIRST means moving from a high position.Then, create a 1-second pause between each LED pattern update.
1-3-07 One-bit Digital Tube
1. Overview
This One-bit Digital Tube can show number from 0 to 9 through signal pins, just like a mini screen. In this project, we design circuit to show numbers with this component. It is also widely used in counters and clocks.
2. Components
ESP32 main board x1 |
74HC595N x1 |
1-bit Digital Tube x1 |
220Ω resistor x8 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
3. Component Knowledge
A 7-segment display is an 8-shaped component which packages 7 LEDs. Each LED is called a segment - when energized, one segment forms part of a numeral to be displayed.
Each of the LEDs in the display is given a positional segment with one of its connection pins led out from the rectangular plastic package.
These LED pins are labeled from “a” through to “g” representing each individual LED.
The other LED pins are connected together forming a common pin.
So by forward biasing the appropriate pins of the LED segments in a particular order, some segments will brighten and others stay dim, thus showing the corresponding character on the display.
Features:
Size: 19 x 12.7 x 13.8mm(LxWxH, include the pin)
Screen: 0.56’’
Color: red
Common Cathode
Forward Voltage: 1.8V
10 pins
Pitch: standard 0.1” (2.54mm)
Common Cathode (CC) or Common Anode (CA)
There are two types of pin connection: Common Cathode (CC) and Common Anode (CA). As the name suggests, a CC display has all the cathodes of the 7 LEDs connected when a CA display has all the anodes of the 7 segments connected.
Common Cathode 7-Segment Display
Common Anode 7-Segment Display
How to Know CC or CA?
Usually there will be label on the side of the 7-segment display, xxxAx or xxxBx. Generally speaking xxxAx stands for common cathode and xxxBx stands for common anode.
You can also use a multimeter to check the 7-segment display if there is no label. Set the multimeter to diode test mode and connect the black lead to the middle pin of the 7-segment display, and the red lead to any other pin except the middle one. The 7-segment display is common cathode if a segment lights up.
You swap the red and black meter heads if there is no segment lit. When a segment is lit, it indicates a common anode.
Display Codes
To help you get to know how 7-segment displays(Common Cathode) display Numbers, we have drawn the following table. Numbers are the number 0-F displayed on the 7-segment display; (DP) GFEDCBA refers to the corresponding LED set to 0 or 1.
For example, 01011011 means that DP, F and C are set to 0, while others are set to 1. Therefore, the number 2 is displayed on the 7-segment display.
In this experiment, we use a common cathode one-bit digital tube 。 As we mentioned above, we connect the common cathode to GND and set pin to “HIGH” to light it up.
4. Wiring Diagram
⚠️Pay attention to the insert direction of the digital tube. Note the dot on the tube.
Schematic diagram:
The schematic diagram here is basically the same as 74HC595, the only difference is that Q0-Q7 are connected to the A-G pins and dp pins of the 8-segment display.
Wiring diagram:
⚠️Pay attention to the insert direction of 74HC595N.
5. Test Code
7 segment for number display and 1 for a dot. For instance, if we show number 1, turn on segment b and c.
/*
* Filename: One_Digit_Display
* Function: 1-bit digital tube shows number 0-9
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int rckPin = 23; //RCK
const int sckPin = 18; //SCK
const int siPin = 5; //SI
int datArray[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void setup (){
//set pins to output
pinMode(rckPin,OUTPUT);
pinMode(sckPin,OUTPUT);
pinMode(siPin,OUTPUT);
}
void loop(){
for(int num = 0; num <10; num++){
digitalWrite(rckPin,LOW); //ground RCK and hold low for as long as you are transmitting
shiftOut(siPin,sckPin,MSBFIRST,datArray[num]);
digitalWrite(rckPin,HIGH); //pull the RCK to save the data
delay(1000);
}
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The digital tube shows integer number from 0-9.
7. Code Explanation
Herein, we use shiftOut()
function writes the binary number to the Shift register.
Suppose it displays numbers “2”. The f , c and dp should turn off (low), while a , b , d , e and g should be turn on (high). “01011011” is binary and “0x5b” is hexadecimal.
Thus, shiftOut(siPin,sckPin,MSBFIRST,0x5b)
is required to show number “2” on the display.
The following table shows the hexadecimal pattern that needs to be written to the shift register in order to display the numbers 0 ~ 9.
Write these codes to shiftOut()
to display the corresponding number.
1-3-08 4-bit Digital Tube
1. Overview
4-bit Digital Tube is very practical for devices such as electronic clocks, score counters and counters of number. In this project, we use ESP32 board to control it to display four digits 0000-9999.
2. Component Knowledge
4-Digit 7-Segment Display
4-Digit 7-segment display consists of four 7- segment displays working together.
The 4-digtal 7-segment display works independently. It uses the principle of human visual persistence to quickly display the characters of each 7-segment in a loop to form continuous strings.
For example, when “1234” is displayed on the display, “1” is displayed on the first 7-segment, and “234” is not displayed. After a period of time, the second 7-segment shows “2”, the 1st 3th 4th of 7-segment does not show, and so on, the four digital display show in turn. This process is very short (typically 5ms), and because of the optical afterglow effect and the principle of visual residue, we can see four characters at the same time.
There are two types of 4-digtal 7-segment display: common anode and common cathode. The display principle is similar to that of a single-digit tube which is controlled by 8 GPIO ports to control the display segments of the digital tube, which are 8 LED lights. However, since this is a four-digit, it also needs 4 GPIO ports to control the digit selection end, which is to select which single digital tube is lit. The switching of the digit is very, and the human eye can’t distinguish it, so it looks like multiple digital tubes are displayed at the same time.
Display Codes
To help you get to know how 7-segment displays(Common Anode) display Numbers, we have drawn the following table. Numbers are the number 0-F displayed on the 7-segment display; (DP) GFEDCBA refers to the corresponding LED set to 0 or 1, For example, 11000000 means that DP and G are set to 1, while others are set to 0. Therefore, the number 0 is displayed on the 7-segment display, while HEX Code corresponds to hexadecimal number.
To help you get to know how 7-segment displays(Common Cathode) display Numbers, we have drawn the following table. Numbers are the number 0-F displayed on the 7-segment display; (DP) GFEDCBA refers to the corresponding LED set to 0 or 1, For example, 00111111 means that DP and G are set to 0, while others are set to 1. Therefore, the number 0 is displayed on the 7-segment display, while HEX Code corresponds to hexadecimal number.
⚠️Note: The 4-digtal 7-segment display used here is a cathode one.
3. Components
ESP32 main board x1 |
4-bit Digital Tube x1 |
220Ω resistor x8 |
breadboard x1 |
jumper wires |
USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
/*
* Filename: Four_Digit_Display
* Function: 1-bit digital tube shows number 0000-9999
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int d_a = 19; //Define segment a to pin 19
const int d_b = 17;
const int d_c = 14;
const int d_d = 13;
const int d_e = 5;
const int d_f = 23;
const int d_g = 27;
const int d_dp = 12;
const int G1 = 18; //Define the first group G1 to pin 18
const int G2 = 26;
const int G3 = 25;
const int G4 = 16;
//Digital tube 0-F code value
unsigned char num[17][8] =
{
//a b c d e f g dp
{1, 1, 1, 1, 1, 1, 0, 0}, //0
{0, 1, 1, 0, 0, 0, 0, 0}, //1
{1, 1, 0, 1, 1, 0, 1, 0}, //2
{1, 1, 1, 1, 0, 0, 1, 0}, //3
{0, 1, 1, 0, 0, 1, 1, 0}, //4
{1, 0, 1, 1, 0, 1, 1, 0}, //5
{1, 0, 1, 1, 1, 1, 1, 0}, //6
{1, 1, 1, 0, 0, 0, 0, 0}, //7
{1, 1, 1, 1, 1, 1, 1, 0}, //8
{1, 1, 1, 1, 0, 1, 1, 0}, //9
{1, 1, 1, 0, 1, 1, 1, 1}, //A
{1, 1, 1, 1, 1, 1, 1, 1}, //B
{1, 0, 0, 1, 1, 1, 0, 1}, //C
{1, 1, 1, 1, 1, 1, 0, 1}, //D
{1, 0, 0, 1, 1, 1, 1, 1}, //E
{1, 0, 0, 0, 1, 1, 1, 1}, //F
{0, 0, 0, 0, 0, 0, 0, 1}, //.
};
void setup(){
pinMode(d_a,OUTPUT); //Set pin d_a to output
pinMode(d_b,OUTPUT);
pinMode(d_c,OUTPUT);
pinMode(d_d,OUTPUT);
pinMode(d_e,OUTPUT);
pinMode(d_f,OUTPUT);
pinMode(d_g,OUTPUT);
pinMode(d_dp,OUTPUT);
pinMode(G1,OUTPUT);
pinMode(G2,OUTPUT);
pinMode(G3,OUTPUT);
pinMode(G4,OUTPUT);
}
void loop(){
//Start counting from 0, gradually increase by 1 to 9999, and repeat
for(int l = 0;l < 10;l++ )
{
for(int k = 0; k < 10;k++)
{
for(int j = 0; j < 10; j++)
{
for(int i = 0;i < 10;i++)
{
//125 flashes per second, equal to one second
//1000/8=125
for(int q = 0;q<125;q++)
{
Display(1,l);//The first digit tube displays the value of l
delay(2);
Display(2,k);
delay(2);
Display(3,j);
delay(2);
Display(4,i);
delay(2);
}
}
}
}
}
}
//Display function: g ranges from 1 to 4, num ranges from 0 to 9
void Display(unsigned char g,unsigned char n)
{
digitalWrite(d_a,LOW); //
digitalWrite(d_b,LOW);
digitalWrite(d_c,LOW);
digitalWrite(d_d,LOW);
digitalWrite(d_e,LOW);
digitalWrite(d_f,LOW);
digitalWrite(d_g,LOW);
digitalWrite(d_dp,LOW);
switch(g) //Make a choice
{
case 1:
digitalWrite(G1,LOW); //Choose the first bit
digitalWrite(G2,HIGH);
digitalWrite(G3,HIGH);
digitalWrite(G4,HIGH);
break;
case 2:
digitalWrite(G1,HIGH);
digitalWrite(G2,LOW); //Choose the second bit
digitalWrite(G3,HIGH);
digitalWrite(G4,HIGH);
break;
case 3:
digitalWrite(G1,HIGH);
digitalWrite(G2,HIGH);
digitalWrite(G3,LOW); //Choose the third bit
digitalWrite(G4,HIGH);
break;
case 4:
digitalWrite(G1,HIGH);
digitalWrite(G2,HIGH);
digitalWrite(G3,HIGH);
digitalWrite(G4,LOW); //Choose the fourth bit
break;
default:break;
}
digitalWrite(d_a,num[n][0]); //a queries the code value table
digitalWrite(d_b,num[n][1]);
digitalWrite(d_c,num[n][2]);
digitalWrite(d_d,num[n][3]);
digitalWrite(d_e,num[n][4]);
digitalWrite(d_f,num[n][5]);
digitalWrite(d_g,num[n][6]);
digitalWrite(d_dp,num[n][7]);
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The digital tube repeatedly shows four same number from 0000-9999.
7. Code Explanation
1. “unsigned” represents an unsigned type; char indicates that num is a character, that is, a static unsigned character is defined as num, and the char variable takes 2 bytes.
unsigned char num
2. This is a two-dimensional array of rows and columns (but the storage is still continuous); Data type array name [number of rows][number of columns]=;
unsigned char num[17][8]
For others, please refer to Project 1-3-01 and 1-3-02 Code Explanation.
1-3-09 Buzzer Beep
1. Overview
Active buzzer is a sound component that is widely used as a sound component for computers, printers, alarms ,electronic toys and phones, timers etc. It comes with an internal vibration source, so it can continuously buzz after connecting to 5V power supply.
In this project, we will use ESP32 board to control the active buzzer to beep.
2. Component Knowledge
(1) Active Buzzer
In the active buzzer, a simple oscillator circuit is integrated to convert constant direct current into pulse signals with a certain frequency. Once it receives a high level, it will emit sound.
However, passive buzzer is without vibration source, so it must be driven by 2k ~ 5k square waves, rather than a DC signal.
They are very similar in appearance, but the passive one buzzer is with a green circuit board, while the active one is with black tape. Passive buzzers are not polar, yet active ones are.
You can learn more about buzzer from Wiki: Buzzer - Wikipedia
(2) Transistor
As buzzer requires large current but GPIO of ESP32 output capability cannot meet this requirement, a NPN transistor is needed to amplify the current.
Transistor is a semiconductor that controls current. It amplifies weak signals or works as a non-contact switch.
According to structures, it can be divided into NPN and PNP. Both of them comes with three electrodes: base(B), collector© and emitter(E). The PN junction between E and B is also named “emitting junction”, and that between C and B is also called “collecting junction”.
You can learn more about transistor from Wiki: P-N junction - Wikipedia
As shown below, the arrow points to the direction of current flow.
When there is current passing between “BE”, “CE” will allow several-folded current pass (amplified by the transistor). At this point, transistor works in the amplifying area. When current between “BE” exceeds a certain value, “CE” will not allow current to increase any longer. Now the transistor works in the saturation area.
Here are the two types of transistor: PNP and NPN
In this kit, we mark PNP transistor as 8550, and NPN as 8050.
It is often used as a switch in digital circuits. As microcontroller’s capacity to output current is very weak, transistor is a perfect choice to amplify current and drive large-current components.
NPN transistor drives buzzer: If GPIO outputs high, current will flow through R1, the transistor will get conducted, and the buzzer will emit sound. If GPIO outputs low, no current flows through R1, so the transistor will not be conducted to enable buzzer to sound.
PNP transistor drives buzzer: If GPIO outputs low, current will flow through R1, the transistor will get conducted, and the buzzer will emit sound. If GPIO outputs high, no current flows through R1, so the transistor will not be conducted to enable buzzer to sound.
3. Components
ESP32 main board x1 |
NPN transistor (S8050) x1 |
active buzzer x1 |
1kΩ resistor x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
10kΩ resistor x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
/*
* Filename: Buzzer Beep
* Function: active buzzer makes sounds
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int buzzerPin = 13; // the buzzer pin
void setup(){
pinMode(buzzerPin, OUTPUT); // Set as output
}
void loop(){
for (int i = 0; i < 50; i++) // Loop 50 times and play a short tone each time
{
digitalWrite(buzzerPin, HIGH); // Set to HIGH to make the buzzer sound
delay(3); // Wait for 3 milliseconds
digitalWrite(buzzerPin, LOW); // LOW to turn off the buzzer
delay(3); //
}
delay(1000); // Wait for 1s before starting the next loop
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The active buzzer in the circuit will beep.
7. Code Explanation
Please refer to Project 1-3-01 Code Explanation.
1-3-10 Play Music
1. Overview
In a previous project, we studied an active buzzer, which can only make one single sound. Unlike it, passive buzzer can emit sounds of different frequencies. In this project, we will control a passive buzzer to play wonderful music.
2. Component Knowledge
A passive buzzer is not integrated with internal vibration source. It must be driven by 2K-5K square waves, rather than DC signals. They are very similar in appearance, but the passive one buzzer is with a green circuit board, while the active one is with black tape. Passive buzzers are not polar, yet active ones are.
3. Components
ESP32 main board x1 |
NPN transistor (S8050) x1 |
passive buzzer x1 |
1kΩ resistor x1 |
breadboard x1 |
jumper wires |
Micro USB cable x1 |
10kΩ resistor x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
/*
* Filename: Play music
* Function: passive buzzer plays music
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
int LEDC_CHANNEL_0 = 0; // The LEDC timer uses channel 0
int LEDC_TIMER_13_BIT = 8; // LEDC timer uses 8-bit precision
const int BUZZER_PIN = 13; // Defines tool I/O ports
// Create a music melody list
int melody[] = {330,330,330,262,330,392,196,262,196,165,220,247,233,220,196,330,392,440,349,392,330,262,294,247,262,196,165,220,247,233,220,196,330,392,440,349,392,330,262,294,247,392,370,330,311,330,208,220,262,220,262,294,392,370,330,311,330,523,523,523,392,370,330,311,330,208,220,262,220,262,294,311,294,262,262,262,262,262,294,330,262,220,196,262,262,262,262,294,330,262,262,262,262,294,330,262,220,196};
// Create a list of tone durations
int noteDurations[] = {8,4,4,8,4,2,2,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,3,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,2,8,8,8,4,4,8,8,4,8,8,3,8,8,8,4,4,4,8,2,8,8,8,4,4,8,8,4,8,8,3,3,3,1,8,4,4,8,4,8,4,8,2,8,4,4,8,4,1,8,4,4,8,4,8,4,8,2};
void setup() {
pinMode(BUZZER_PIN, OUTPUT); // Set the buzzer to output mode
}
void loop() {
int noteDuration; // Create a variable called noteDuration
for (int i = 0; i < sizeof(noteDurations); ++i){
noteDuration = 800/noteDurations[i];
ledcSetup(LEDC_CHANNEL_0, melody[i]*2, LEDC_TIMER_13_BIT);
ledcAttachPin(BUZZER_PIN, LEDC_CHANNEL_0);
ledcWrite(LEDC_CHANNEL_0, 50);
delay(noteDuration * 1.30); // Delay
}
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The passive buzzer in the circuit plays music.
7. Code Explanation
1. Define buzzer pins and PWM channels, accuracy, and resolution constants.
int LEDC_CHANNEL_0 = 0; // The LEDC timer uses channel 0
int LEDC_TIMER_13_BIT = 13; // LEDC timer uses 13 bit accuracy
const int BUZZER_PIN = 14; // Defines tool I/O ports
2. Define two arrays that contain the musical melody (in Hz) and the tone duration.
// Create a music melody list
int melody[] = {330,330,330,262,330,392,196,262,196,165,220,247,233,220,196,330,392,440,349,392,330,262,294,247,262,196,165,220,247,233,220,196,330,392,440,349,392,330,262,294,247,392,370,330,311,330,208,220,262,220,262,294,392,370,330,311,330,523,523,523,392,370,330,311,330,208,220,262,220,262,294,311,294,262,262,262,262,262,294,330,262,220,196,262,262,262,262,294,330,262,262,262,262,294,330,262,220,196};
// Create a list of tone durations
int noteDurations[] = {8,4,4,8,4,2,2,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,3,3,3,3,4,4,8,4,8,8,8,4,8,4,3,8,8,2,8,8,8,4,4,8,8,4,8,8,3,8,8,8,4,4,4,8,2,8,8,8,4,4,8,8,4,8,8,3,3,3,1,8,4,4,8,4,8,4,8,2,8,4,4,8,4,1,8,4,4,8,4,8,4,8,2};
1-3-11 Small Fan
1.Overview
In hot summer, we need electric fans to cool us down, so in this project, we control 130 motor with transistor and ESP32 board to rotate the fan.
2. Components
ESP32 main board x1 |
130 motor x1 |
M-F DuPont wires |
Micro USB cable x1 |
AA battery (self-provided) x6 |
fan x1 |
battery holder x1 |
3. Component Knowledge
130 motor:
It uses HR1124S motor control chip that is a single channel H-bridge driver chip used in DC motor solutions. The H-bridge driving part adopts PMOS and NMOS power tubes with low on-resistance, which ensures low power loss of the chip and makes the chip work safely for a longer time. In addition, the HR1124S supports low standby current and low static operating current, which makes the 130 motor module easy to use in toys.
130 motor parameters:
Operating voltage: 5V
Operating current: ≤200MA
Operating power: 2W
Operating temperature: -10℃~+50℃
130 motor working principle:
The HR1124S chip helps drive the motor, which cannot be driven by a triode or directly driven by an IO port because of the large current required by the motor.
The motor can be turned by adding a voltage to both ends. If the voltage direction is different, the direction of rotation of the motor is not the same. Within the limit voltage, the higher the voltage is, the faster the motor will rotate; On the other hand, the lower the voltage is, the slower the motor will rotate, or stop.
There are two control methods: one is high and low level (control on and off), and the other is PWM(control speed).
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
⚠️Wire up first and then mount the fan to the motor.
5. Test Code
/*
* Filename: Small_Fan
* Function: fan rotates
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
const int Motorla = 13; // motor Motor_IN+ pin
const int Motorlb = 12; // motor Motor_IN- pin
void setup(){
pinMode(Motorla, OUTPUT);// set Motorla to OUTPUT
pinMode(Motorlb, OUTPUT);// set Motorlb to OUTPUT
}
void loop(){
// set to rotate clockwise for 5s
digitalWrite(Motorla,HIGH);
digitalWrite(Motorlb,LOW);
delay(5000);
// set to stop rotating for 2s
digitalWrite(Motorla,LOW);
digitalWrite(Motorlb,LOW);
delay(2000);
// set to rotate counterclockwise for 5s
digitalWrite(Motorla,LOW);
digitalWrite(Motorlb,HIGH);
delay(5000);
// set to stop rotating for 2s
digitalWrite(Motorla,LOW);
digitalWrite(Motorlb,LOW);
delay(2000);
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The fan rotates the fan rotates counterclockwise for 5 seconds and stops for 2 seconds, and then it rotates clockwise for 5 seconds and stops for 2 seconds. It repeats these actions.
7. Code Explanation
Please refer to Project 1-3-01 Code Explanation.
1-3-12 Servo Rotation
1. Overview
A servo is a position-based device capable of maintaining a specific Angle and providing precise rotation angles. So it is ideal for applications that require consistent Angle adjustment, such as remote controlled toys, airplane models, submarine replica, as well as complex robots.
In this project, we control the servo to rotate to certain angles
2. Parameters
Operating voltage: DC 3.3V~5V
Operating temperature: -10°C ~ +50°C
Dimensions: 32.25mm x 12.25mm x 30.42mm
Port: 2.54mm pitch, 3-pin port
3. Principle
Servo is a kind of position driver, which is mainly composed of housing, DC motor, circuit board, variable gear group with torque, a potentiometer and a control board.
The angle range of most servos is 180 degrees.
As the output torque of the servos is higher than that of DC motors, so they are widely used to control model of cars, planes and robots.
Generally, servo comes with three wires, two of which are used for the power positive (2-positive wire, red) and negative (3-negative wire, brown). The remaining one is for signal (1-signal wire, orange).
We drive the servo via PWM signals, whose duty cycle is fixed and frequency is 50Hz. In a single PWM cycle, the high level duration is 0.5ms ~ 2.5ms, which corresponds linearly to 0° ~ 180° of the servo. Some corresponding values are as follows:
Change the signal value of the servo and it will rotate to the specified angle.
⚠️Note that the angle may vary from servos of different brands after receiving the same signal.
4. Components
ESP32 main board x1 |
servo x1 |
Micro USB cable x1 |
5. Wiring Diagram
Schematic diagram:
Wiring diagram:
6. Test Code
/*
* Filename: Servo Rotation
* Function: servo rotates
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
#include <ESP32Servo.h>
// Define the servo and the pin it is connected to
Servo myServo;
const int servoPin = 4;
// Define the minimum and maximum pulse widths for the servo
const int minPulseWidth = 500; // 0.5 ms
const int maxPulseWidth = 2500; // 2.5 ms
void setup() {
// Attach the servo to the specified pin and set its pulse width range
myServo.attach(servoPin, minPulseWidth, maxPulseWidth);
// Set the PWM frequency for the servo
myServo.setPeriodHertz(50); // Standard 50Hz servo
}
void loop() {
// Rotate the servo from 0 to 180 degrees
for (int angle = 0; angle <= 180; angle++) {
int pulseWidth = map(angle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);
delay(15);
}
// Rotate the servo from 180 to 0 degrees
for (int angle = 180; angle >= 0; angle--) {
int pulseWidth = map(angle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);
delay(15);
}
}
7. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. If a prompt shows “Servo.h: No such file or directory”, please import library referring to 1-1-5 Import Arduino Library or can click Import Arduino Library to refer to import library.
After uploading the code, unplug the USB cable and wire up. Connect the board to the computer with USB cable and the servo rotates forwards and backwards within 0 to 180 degree.
8. Code Explanation
1. include ESP32Servo library: Import the ESP32Servo library, which is required to control the servo.
#include <ESP32Servo.h>
2. Define servo and the pins to which it connects: declares a Servo object(myServo), the constant(servoPin) is the servo pin 25.
// Define the servo and the pin it is connected to
Servo myServo;
const int servoPin = 25;
3. Set the minimum and maximum pulse widths for servo (0.5 ms and 2.5 ms, respectively).
// Define the minimum and maximum pulse widths for the servo
const int minPulseWidth = 500; // 0.5 ms
const int maxPulseWidth = 2500; // 2.5 ms
4. setup() initializes servo by connecting servo to a specified pin and setting its pulse width range, and sets the PWM frequency of servo to standard 50Hz.
void setup() {
// Attach the servo to the specified pin and set its pulse width range
myServo.attach(servoPin, minPulseWidth, maxPulseWidth);
// Set the PWM frequency for the servo
myServo.setPeriodHertz(50); // Standard 50Hz servo
}
attach (int pin, int min, int max)
: Connect servo to the specified GPIO pin and set the minimum and maximum pulse widths for servo.pin
: The GPIO pin number of the servo connection.min
andmax
pulse width that define the range of motion of the servo motor.
setPeriodHertz(int hertz)
: Set the PWM frequency of the servo motor in Hertz.hertz
: The required PWM frequency in Hertz. servo’s default PWM frequency is 50Hz, which is suitable for most applications.
5. loop()
is the main part of the code that runs continuously. It rotates servo from 0 to 180 degrees and then back to 0 degrees. This is done by mapping the Angle to the corresponding pulse width and updating the servo with the new pulse width value.
void loop() {
// Rotate the servo from 0 to 180 degrees
for (int angle = 0; angle <= 180; angle++) {
int pulseWidth = map(angle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);
delay(15);
}
// Rotate the servo from 180 to 0 degrees
for (int angle = 180; angle >= 0; angle--) {
int pulseWidth = map(angle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);
delay(15);
}
}
writeMicroseconds(int value)
: Set the pulse width of the servo motor in microseconds.value
: The desired pulse width, in microseconds.writeMicroseconds(int value)
takes integers as its argument, representing the desired pulse width in microseconds. This value should normally be located atminPulseWidth
andmaxPulseWidth
. Then set the pulse width of the servo motor so that it moves to the corresponding position.
1-3-13 Stepper Motor
1. Overview
In this project, we will control stepper motor(28BYJ-48) with ULN2003 driver and the ESP32 main board. They are used in a variety of applications, such as 3D printers, CNC machines, robots, and common household appliances. Their precise control allows for complex movements, making them ideal for projects requiring high positioning accuracy.
The 28BYJ-48 stepper motor here will rotate in different speed and direction. By understanding how to control the stepper motors, you will smoothly integrate them into your own electronics projects.
2. Component Knowledge
Stepper Motor
It is a motor controlled by a series of electromagnetic coils. It can rotate by the exact number of degrees (or steps) needed, allowing you to move it to a precise position and keep it there. It does this by supplying power to the coil inside the motor in a very short time, but you must always supply power to the motor to keep it in the position you want. There are two basic types of stepping motors, namely uni-polar stepping motor and bipolar stepping motor. In this project, we use a 28-BYJ48 uni-polar stepper motor.
28BYJ-48 Working Principle
The stepper motor is mainly composed of a stator and a rotor. The stator is fixed. As shown in the figure below, the part of the coil group A, B, C, and D will generate a magnetic field when the coil group is energized. The rotor is the rotating part. As follows, the middle part of the stator, two poles are permanent magnets.
Single -phase four beat: At the beginning, the coils of group A are turned on, and the poles of the rotor point at A coil. Next, the group A coil are disconnected, and the group B coils are turned on. The rotor will turn clockwise to the group B. Then, group B is disconnected, group C is turned on, and the rotor is turned to group C. After that, group C is disconnected, and group D is turned on, and the rotor is turned to group D. Finally, group D is disconnected, group A is turned on, and the rotor is turned to group A coils. Therefore, rotor turns 180° and continuously rotates B-C-D-A, which means it runs a circle (eight phase). As shown below, he rotation principle of stepper motor is A - B - C - D - A…
You make order inverse(D - C - B - A - D …) if you want to make stepper motor rotate anticlockwise.
Half-phase and eight beat: 8 beat adopts single and dual beat way,A - AB - B - BC - C - CD - D - DA - A …,rotor will rotate half phase in this order. For example, when A coil is electrified, rotor faces to A coil, then A and B coil are connected, on this condition, the strongest magnetic field produced lies in the central part of AB coil, which means rotating half-phase clockwise.
Parameters
The rotor rotates one circle when the stepper motor we provide rotates 32 phases and with the output shaft driven by 1:64 reduction geared set. Therefore the rotation (a circle) of output shaft requires 32 * 64 = 2048 phases.
The step angle of 4-beat mode of 5V and 4-phase stepper motor is 11.25. And the step angle of 8-beat mode is 5.625, the reduction ratio is 1:64.
Drive Board for ULN2003 Stepper Motor
Drive Board for ULN2003 Stepper Motor converts the weak signal into a stronger control signal to drive the stepper motor.
The following schematic diagram shows how to use the ULN2003 stepper motor driver board interface to connect a unipolar stepper motor to the pins of the ESP32, and shows how to use four TIP120 interfaces.
3. Components
ESP32 main board x1 |
ULN2003 stepper motor drive board x1 |
Stepper motor x1 |
battery holder x1 |
M-F DuPont wires |
AA battery (self-provided) x6 |
Micro USB cable x1 |
4. Wiring Diagram
Schematic diagram:
Wiring diagram:
5. Test Code
/*
* Filename: Stepper_Motor
* Function: stepper motor rotates
* Compiling IDE:ARDUINO 2.3.3
* Author: https://www.keyestudio.com/
*/
// connect stepper motor pins IN1, IN2, IN3 and IN4 to IO16, IO17, IO18 and IO19, respectively
const int outPorts[] = {16, 17, 18, 19};
void setup() {
// Set the pin of the stepper motor drive board to output mode
for (int i = 0; i < 4; i++) {
pinMode(outPorts[i], OUTPUT);
}
}
void loop(){
// The stepper motor rotates once
moveSteps(true, 32 * 64, 3);
delay(1000);
// The stepper motor rotates once in the other direction
moveSteps(false, 32 * 64, 3);
delay(1000);
}
//Recommendation: When the motor rotates accurately, the millisecond range is 3 to 20
void moveSteps(bool dir, int steps, byte ms) {
for (unsigned long i = 0; i < steps; i++) {
moveOneStep(dir); // move one step
delay(constrain(ms,3,20)); // control speed
}
}
void moveOneStep(bool dir) {
// Define a variable that uses four lows to represent the state of the port
static byte out = 0x01;
// Determine the shift direction according to the direction of rotation
if (dir) { // move left
out != 0x08 ? out = out << 1 : out = 0x01;
}
else { // move right
out != 0x01 ? out = out >> 1 : out = 0x08;
}
// Output signals to each port
for (int i = 0; i < 4; i++) {
digitalWrite(outPorts[i], (out & (0x01 << i)) ? HIGH : LOW);
}
}
void moveAround(bool dir, int turns, byte ms){
for(int i=0;i<turns;i++)
moveSteps(dir,32*64,ms);
}
void moveAngle(bool dir, int angle, byte ms){
moveSteps(dir,(angle*32*64/360),ms);
}
6. Test Result
Choose the board model(ESP32 Dev Module) and port(COMxx), and click to upload code. After uploading the code, power the ESP32 board. The D1, D2, D3 and D4 leds on the ULN2003 drive module are turned on, and the stepper motor rotates in two directions and maintains this state cycle.
7. Code Explanation
1. Initializes the control pins of the Stepper motor drive board.
// Digital port connected to Stepper motor drive board
int outPorts[] = {16, 17, 18, 19};
outPorts[] = {pin1, pin2, pin3, pin4}
: Creates a new instance of the outPorts[] class that represents a specific Stepper motor connected to the ESP32 main board. pin1, pin2, pin3, and pin4 correspond to IN1, IN3, IN2, and IN4 pins on ULN2003 drives.
2. loop()
void loop(){
// Stepper motor rotate once
moveSteps(true, 32 * 64, 3);
delay(1000);
// Stepper motor rotate once the other direction
moveSteps(false, 32 * 64, 3);
delay(1000);
}
The main program continuously rotates the Stepper motor, completing a full clockwise turn at 3 RPM, followed by a full counter-clockwise turn at 3 RPM.
moveSteps(true, 32 * 64, 3);
andmoveSteps(false, 32 * 64, 3);
: Set the motor speed, direction, and number of steps (2038 steps) in revolutions per minute (RPM).true
: Forward rotation.false
: Reverse rotation.