Professional Documents
Culture Documents
Hallberg Gary - Wireless Communications With Arduino and The ESP32 (Arduino Short Reads. Book 7) - 2021
Hallberg Gary - Wireless Communications With Arduino and The ESP32 (Arduino Short Reads. Book 7) - 2021
the ESP32
Book 7 of the Arduino Short Reads Series
Gary Hallberg
The idea underpinning the Arduino short reads series is to provide a comprehensive, easy to follow
tutorial set and reference guide for anybody wanting to learn about Arduino and basic electronics.
Having a short reads series means that students and hobbyists can select key topics of interest in the
field with minimal outlay. The series aims to provide an easy introduction to all topics of interest and
expand on these topics to provide a broader and deeper understanding of that focus area. The books
are currently only available in Kindle format to provide a very inexpensive package backed up by video
content and interactive social media.
The series is aimed at youngsters and adults interested in getting into electronics and it takes a modern
approach, combining the use of the inexpensive software driven Arduino controller board, with a
multitude of sensors and discreet electronic components. The experiments in this series of books are
easy to follow, inexpensive to implement and compelling for all interested in STEM education. I hope
to inspire anybody looking for a future career in technology or to simply to have fun.
The first book of this series looks at the Arduino microcontroller and explains its operation and purpose.
Experiments look to show you how to set up the programming environment and drive LEDs as well as
read input from switches, thermistors and photocells. Book 1 will give you a solid foundation of how
some basic electronic components work and how to use them to make simple designs.
Book 8 in this Arduino Short Reads Series is still being written but the series focuses on the following:
• Book 1 – First Steps with Arduino (published)
• Book 2 – Working with Displays (published)
• Book 3 – Controlling Motors (published)
• Book 4 – Range Finding, Object Detection and Object Avoidance (published)
• Book 5 – Building a Simple Rover (published)
• Book 6 – Arduino Special Functions (published)
• Book 8 – The Arduino Leonardo
If you find this series of books useful then please leave your review and rating on
Amazon.
Follow North Border Tech Training on Facebook and Twitter for the latest news and
insights as to how this series will develop.
Foreword
When we look at current trends in technology, we often come across the term “Internet of Things” or
IoT for short. IoT is a broad term that can be applied to the myriad of smart devices in home, education,
and industry. Arduino is an excellent IoT learning platform. However, we have not yet covered a
fundamental aspect of IoT and that is the ability for smart device to communicate with each other over
wireless networks and the Internet. It is this part of our journey with Arduino that we will explore in
this book. We will take time to understand some basic aspects of Electromagnetic Radiation and how
radio works. We will look at basic Radio Frequency communications and dig deeper into Bluetooth.
Finally, we will learn about WiFi and the Internet and how we can use Arduino and related devices to
create web enabled projects.
We will deviate away from the native Arduino platform to look at the ESP32. The ESP32 is an extremely
capable microcontroller with integrated Bluetooth and WiFi that is both low cost and compatible with
the Arduino IDE. We will be clear about the benefits of using this platform compared to the native
Arduino devices.
Some of the concepts presented here are complex, so I will generalize when needed. I will also keep the
Arduino control aspects of the Experiments simple so as not to detract from the communications
elements of the experiments. That said, I have no doubt the skills learnt here will allow you to develop
more engaging and useful projects. Without further delay let us get into the content.
Prerequisites for this Book
This book assumes you have read Book 1 of the series (‘First Steps with Arduino’) or you already have
some experience of the Arduino platform, how to set up the IDE and undertake some basic Arduino
programming tasks. Basic functions such as ‘digitalRead’ and ‘digitalWrite’ are not covered here
but are explained in Book 1.
Download the Code
You can download the Arduino Code for the experiments in this book from GitHub using the link below.
https://github.com/ghallberg-nbtt/congenial-robot
I recommend that you do this as I have removed some of the comments from the code in the book
listings to aid readability in print form. I strongly recommend that you comment your code heavily to
facilitate understanding and to become familiar with best engineering practice.
Chapter 1: Radio Frequency Communications
with Arduino
In this chapter we will look at some basic radio communications within the Arduino Uno. You will be
familiar with key fobs that control car doors, doorbells, or devices remotely on a button press. These
are all radio devices that we can integrate into our Arduino projects. We start by learning a little about
what radio is.
What is Radio?
Radio waves are part of the Electromagnetic Spectrum, and we can control these waves to transmit
voice and data. Electromagnetic waves are all around us. They form visible light, radiation, microwaves.
All these phenomena are the same thing but radiate at different frequencies and wavelengths. Figure 1-
1 is an image produced by NASA that illustrates the Electromagnetic Spectrum very well.
Figure 1-1: The Electromagnetic Spectrum
Image source: Courtesy of NASA
We can represent the type of Electromagnetic Radiation in terms of frequency and wavelength. You can
see from Figure 1-1 that light oscillates like a wave and takes a sinusoidal form. The wave become more
compacted at the high end where Gamma Waves exist compared to the low end where AM radio exists.
The frequency is represented by the number of oscillation repetitions in 1 second. The unit of
measurement being ‘Hertz’ or Cycles Per Second. Hertz is presented by the letters ‘Hz’.
The wavelength is a measure of the length of a single oscillation and is calculated using the speed of
light in free space. The speed of light is a constant and is about 300,000Km/s in the vacuum of space,
but is slower for other media such as glass. The formula for wavelength calculation is represented below.
𝐶
𝜆=
𝑓
‘λ’ represents wavelength, ‘C’ is the speed of light and ‘f’ represents frequency.
We often use wavelengths in electronics. When we want a specific color of LED the datasheet will specify
the wavelength of that component. A red LED typically has a wavelength of 630nm. Infrared LEDs used
in remotes or for transmitting data over a fiber optic cable may have wavelengths of 850nm or 1310nm.
Infrared is just outside the range that the human eye can detect. Human visible light has wavelengths
between 380nm and 750nm.
It is important to understand wavelength and frequency in the context of radio transmissions. You need
to be aware of what frequencies you are using and the devices around you are using. Radio spectrum is
largely controlled by in-country authorities. There are some frequencies allocated to bodies such as
police and emergency services, TV, and radio. There are parts of the spectrum that are set aside for
other uses such as WiFi and cellular communications. Although you can generally use these frequencies
for your own projects, there are still rules that need to be adhered to such a maximum transmit power.
In the United States, the Federal Communications Commission (FCC) are the licensing authority. The
authority in the EU is the Comité International Spécial des Perturbations Radioélectriques (CISPR) and
Industry Canada (IC) for Canada. Generally, spectrum allocation across these authorities is consistent,
but there are some local differences, and you should check that any equipment you plan to use is
compliant with your local authority’s regulations.
The radio-controlled button unit used in this chapter operates at 433Mhz. This frequency is free to use
for this sort of application in Europe and the United States. But that same device may operate at
315MHz in the United States. It is not permitted to use 315Mhz in Europe. Therefore, you must ensure
you have the local variant that is legal to use in your area.
//Setup inputs
const int D0 = 2;
const int D1 = 3;
const int D2 = 4;
const int D3 = 5;
//setup LEDs
const int LED0 = 8;
const int LED1 = 9;
const int LED2 = 10;
const int LED3 = 11;
void setup() {
pinMode (D0, INPUT);
pinMode (D1, INPUT);
pinMode (D2, INPUT);
pinMode (D3, INPUT);
pinMode (LED0, OUTPUT);
pinMode (LED1, OUTPUT);
pinMode (LED2, OUTPUT);
pinMode (LED3, OUTPUT);
currentD0State = digitalRead(D0);
currentD1State = digitalRead(D1);
currentD2State = digitalRead(D2);
currentD3State = digitalRead(D3);
}
void loop() {
//read D0 state and toggle LED0 on state change
lastD0State = currentD0State; // save the last state
currentD0State = digitalRead(D0); // read new state
Summary
In this chapter you learnt about the basics of Electro Magnetic (EM) radiation and where radio waves
sit in the EM spectrum. You learnt about the basics of Amplitude and Frequency Modulation and how
the techniques can be used to encode voice and data signals. You learnt how to use a basic 4-channel
radio receiver to toggle LEDs.
Chapter 2: The Espressif Systems ESP32
In this chapter we will learn about the Espressif Systems ESP32 microcontroller. This microcontroller
will be used for the experiments in the remaining chapters of this book. We will investigate the reasons
for changing from the native Arduino products to the ESP32 and explore the benefits of using the
Arduino IDE to program this device.
Arduino or ESP32?
It is a fair question to ask whether you should use the ESP32 over native Arduino MCUs for all projects
and not just for communications. Afterall, the ESP32 is cheaper, has more I/O capability, more PWM
capability, more communications buses, and special functions such as ADC converters and touch
sensitive inputs. Furthermore, it is compatible with the Arduino IDE.
There are some good arguments to use native Arduino boards especially when starting out with
electronics and coding. Boards like the Arduino Uno have been around for a lot longer than the ESP32.
The Arduino Uno was released in 2010 and the ESP32 in 2016. As a result, the Arduino Uno has a much
greater following and there is much more learning and project material available on the Web and in
books. The Arduino Uno can accommodate shields whereas the ESP32 cannot, and there are many
shields available for the Arduino Uno. The Arduino Uno supports both 3.3V and 5V logic whereas the
ESP32 only supports 3.3V. Some peripherals only support 5V logic and you will find that some
transistors will not turn fully on or off using 3.3V logic. So really, you need to make the choice based on
the resources you have and the needs of any given project.
Experiment 2: Enabling the Arduino IDE for the ESP32 and Testing
your Environment
In this experiment, you will enhance your Arduino IDE so that it supports the ESP32. You will also test
the installation using a preinstalled example Sketch. For this experiment, we assume your IDE is
installed and working for the native Arduino environment and that a WiFi network is within range.
You first need to start by adding the location of the Espressif Systems ESP32 addon for the Arduino
IDE that makes to ESP32 available. From the IDE, select File > Preferences as in Figure 2-2.
Figure 2-2: The Arduino Preferences Location
Image source: The Arduino IDE
The dialog box as in Figure 2-3 will appear.
Summary
In this chapter you learnt about the Espressif Systems ESP32 controller and its rich array of functions.
You compared the ESP32 with the Arduino and learnt about the advantages and disadvantages of using
one over the other. You learnt how to integrate the ESP32 into the Arduino IDE and tested the board
with a ‘WiFi scan’ example.
Chapter 3: Bluetooth Communications with
the ESP32
In previous books within this series, we have looked at Bluetooth communications primarily to transmit
serial data. There is so much more to the technology, and we can get the best out if it with the ESP32.
We can dig a little deeper into the capabilities of Bluetooth which is one of the world’s most popular
wireless standards. Amongst other things, variants of Bluetooth technology are used in headsets,
keyboards, smartphones, and computer mice.
What is Bluetooth?
Over the years Bluetooth has evolved into many forms to support devices and implementations can vary
from device to device. Therefore, it is worth digging a little deeper to understand the various Bluetooth
incarnations.
Bluetooth was first standardized by the Institute of Electrical and Electronic Engineers as IEEE
802.15.1. It is now managed by the Bluetooth Special Interest Group.
Bluetooth specifications have evolved since through several versions and each version adds new
features. The first release was in 1998 and was primarily used for wireless replacement of serial links.
Bluetooth 2.0 was released in 2004 and added faster speeds. It was the first version to pave the way for
Bluetooth audio connectivity. These early versions did have problems pairing devices. Bluetooth 3.0
was released in 2009 and gained popularity as it was integrated into many cell phones for hands free
operation as well as radios and other devices.
The most important release was Bluetooth 4.0 that came to light in 2013. Bluetooth 4.0 introduced
Bluetooth Low Energy (BTLE or BLE). Bluetooth 4.0 is also referred to as Bluetooth Smart. To maintain
backward compatibility, Bluetooth 4.0 is split into 2 parts: Bluetooth Classic and Bluetooth Low Energy.
Bluetooth Classic is there to maintain backward compatibility with older implementations but has some
enhancements for higher speed and audio streaming but consumes more power. Bluetooth Low Energy
consumes less power and was designed for use in battery power devices that do not consume much
bandwidth. Such devices would be heart monitors, environmental sensors, and home smart devices.
These devices are only ‘active’ for some of the time during which they will transmit their data and then
go into a ‘sleep’ mode.
Bluetooth operates in the 2.4-2.5GHz ISM radio band and most modern chips support Bluetooth Classic
and BTLE. Or just BTLE.
Bluetooth Profiles
Before moving onto some practical work, it is first worth introducing you to the concept of a Bluetooth
profile. Different Bluetooth devices support difference Bluetooth profiles. A profile can be viewed as an
application for different tasks. For instance, an audio headset will most likely support the Advanced
Audio Distribution Profile (A2DP) for streaming music, but not the File Transfer Protocol (FTP). When
Bluetooth devices first communicate together, they tell each other what profiles they support. In this
way your tablet knows it can send music to your headphones, but not your Bluetooth fitness monitor.
BTLE supports a particular profile called Generic Attribute (GATT). GATT defines a data structure for
exchanging information between 2 BTLE enabled devices. GATT focuses on transmitting small chunks
of specifically formatted data in short bursts and so consumes less power. This would not be possible
with an audio streaming profile.
The Bluetooth SIG has predefined some GATT service such a blood pressure monitoring service and
battery monitoring service. You can still define your own service or use any of the pre-defined services.
You can reduce the size of library compiled by enabling only those
modules that you want to
use.For this first define CUSTOM_SETTINGS followed by defining
INCLUDE_modulename.
void loop() {
To refresh the data that the device has received from the mobile app, you must use the following line of
code:
Dabble.processInput();
This function also changes the state and the brightness of the LED automatically and you don’t have to
do anything else. Pretty simple!
The Accelerometer
For the next experiment we will use the Smartphone’s accelerometer to change the color and intensity
of the RGB LED. Before we tackle that experiment it is worth understanding what an accelerator is. As
the name implies, it measures acceleration and with most smartphones it measures acceleration in 3
dimensions. A smartphone will most likely have a gyroscope and magnetometer. Gyroscopes measure
rotation movement and magnetometers measure magnetic fields. It is important to know that
accelerometers measure linear acceleration. It is these three sensors used in combination that work
with your smartphone’s mapping apps. The accelerometer is used to work out the phone orientation.
The z-axis and it always experiences an acceleration of 9.8m/s2. When in freefall this acceleration will
be 0m/s2.
Figure 3-3 is a simplified diagram of a single dimension of an accelerometer. These devices are built
onto silicon like other ICs and are a few microns wide.
Figure 3-3: A Simplified View of an Accelerometer
Image source: The author
In Figure 3-3, the blue elements are fixed, and the orange-colored elements can move while attached to
the springs. When the accelerometer is subjected to acceleration the distance between the movable
mass and the fixed plate will change. This will lead to a change in the capacitance between the movable
mass and the fixed plates. This capacitance can be measured and correlated to a specific acceleration.
You can reduce the size of library compiled by enabling only those
modules that you wan to
use. For this first define CUSTOM_SETTINGS followed by defining
INCLUDE_modulename.
void loop() {
Dabble.processInput();
print_Accelerometer_data();
}
void print_Accelerometer_data()
{
Serial.print("X_axis: ");
Serial.print(Sensor.getAccelerometerXaxis(), 4);
Serial.print('\t');
Serial.print("Y_axis: ");
Serial.print(Sensor.getAccelerometerYaxis(), 4);
Serial.print('\t');
Serial.print("Z_axis: ");
Serial.println(Sensor.getAccelerometerZaxis(), 4);
Serial.println();
}
Listing 3-2: The Predefined Dabble Sketch to Control the Smartphone Sensors
Listing source: STEMpedia with comments rearranged for book readability
You can see it is like the code use in Experiment 3. You need to load the custom settings, the library and
include the sensor module.
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
The ‘processInput()’ function of the ‘Dabble’ class does the work in communicating with your
Smartphone.
Dabble.processInput();
The ‘Dabble’ class predefines some functions we can use to get the acceleration in the X, Y and Z axis
and these are shown in Table 3-1. We use these to print the acceleration the serial monitor and you
should open the serial monitor when running the Sketch.
Function Return Type Description
Sensor.getAccelerometerXaxis() Float Returns Accelerometer X value in m/s2
Sensor.getAccelerometerYaxis() Float Returns Accelerometer Y value in m/s2
Sensor.getAccelerometerZaxis() Float Returns Accelerometer Z value in m/s2
You can reduce the size of library compiled by enabling only those modules
that you wan to use. For this first define CUSTOM_SETTINGS followed by
defining INCLUDE_modulename.
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200);
Dabble.begin("MyEsp32");
void loop() {
Dabble.processInput();
print_Accelerometer_data();
delay (15);
}
void print_Accelerometer_data()
{
Serial.print("X_axis: ");
Serial.print(Sensor.getAccelerometerXaxis(), 4);
Serial.print('\t');
Serial.print("Y_axis: ");
Serial.print(Sensor.getAccelerometerYaxis(), 4);
Serial.print('\t');
Serial.print("Z_axis: ");
Serial.println(Sensor.getAccelerometerZaxis(), 4);
Serial.println();
Finally, we need to set a PWM resolution. This can be between 1 and 16 bits but setting the value to 8
bits will give us 256 values between 0 and 255.
const int RESOLUTION = 8;
The ESP32 library has some special functions to control LEDs using PWM. These are ‘ledcSetup’,
‘ledcAttachPin’ and ‘ledcWrite’. The familiar ‘digitalWrite’ function can be used for basic
on/off functionality. The ‘ledcSetup’ function sets up the basic PWM parameters and associates them
to a PWM channel. It has the following usage:
ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
So, in our Sketch we have:
ledcSetup(RED_LED_CHANNEL, FREQ, RESOLUTION);
ledcSetup(GREEN_LED_CHANNEL, FREQ, RESOLUTION);
ledcSetup(BLUE_LED_CHANNEL, FREQ, RESOLUTION);
We then assign to PWM channel to a GPIO pin using the ‘ledcAttachPin’ function.
ledcAttachPin(RED_LED, RED_LED_CHANNEL);
ledcAttachPin(GREEN_LED, GREEN_LED_CHANNEL);
ledcAttachPin(BLUE_LED, BLUE_LED_CHANNEL);
The ‘ledcWrite’ function is used to write a PWM duty cycle to the GPIO pin. The function has the
following usage:
ledcWrite(uint8_t channel, uint32_t duty);
That is the setup for our Sketch complete and in the main ‘loop’ we first want to read the accelerometer
values which are returned as floating-point values and convert them integers prior to mapping them a
PWM value. We can ‘cast’ the floating-point values to integer by preceding the floating-point values
with ‘(int)’. Any fractional part is simply discarded.
float valRed = Sensor.getAccelerometerXaxis();
float valGreen = Sensor.getAccelerometerYaxis();
float valBlue = Sensor.getAccelerometerZaxis();
We now need to convert the acceleration to a PWM value. We do this by using the ‘map’ function. The
‘map’ function has the following usage.
map(value, fromLow, fromHigh, toLow, toHigh)
We can reuse the variable past as the ‘value’ argument. I decided to map an acceleration of -5m/s2 to
a PWM value of 0 and +5m/s2 to a PWM value of 255. Note that the ‘map’ function does not constrain
the minimum or maximum value and acceleration values outside of our bounds will return a value less
than 0 or greater than 255. This is not good for PWM operation and so we need to constrain the value
using the ‘contrain’ function. The ‘constrain’ function is simple to follow and values less than 0 are
constrained to 0 and values greater than 255 are contained to 255. Every other value is left as is.
valRed_int = constrain (valRed_int, 0, 255); //constrain PWM range
valGreen_int = constrain (valGreen_int, 0, 255); //constrain PWM range
valBlue_int - constrain (valBlue_int, 0, 255); //constrain PWM range
Our final task is to write the PWM values to the RGB LED.
ledcWrite(RED_LED_CHANNEL, valRed_int); //write value to LED
ledcWrite(GREEN_LED_CHANNEL, valGreen_int); //write value to LED
ledcWrite(BLUE_LED, valBlue_int); //write value to LED
Summary
In this chapter you learnt about the principles of Bluetooth and the capabilities of the various versions.
You learnt that the Bluetooth standards are managed by the Bluetooth Special Interest Group. You
learnt that Bluetooth 4.0 introduced Bluetooth Low Energy (BTLE or BLE) and that this is ideal for
when short burst of information needs to be exchanged. You learnt that Bluetooth Classic is ideal for
streaming applications. You learnt that there are Smartphone apps available that allow you to
connection with the ESP32 and Arduino boards using BLE and Bluetooth Classic. You learnt how to
program PWM channels on the ESP32 to control an LED.
Chapter 4: Wi-Fi and the Internet
We cannot learn about Arduino and ESP32 wireless communication without looking at Wi-Fi and the
Internet. The issue I have is that I could write several books on the subject and trying to condense the
key elements into just 1 chapter will present some challenges. We also must bear in mind that this is a
complex subject, and I cannot lose sight of the fact that this series of books is aimed at the pure
beginner. Therefore, I will keep the explanations light and make some generalizations so that you are
able to better understand the concepts. I have always found that with IP networking, it is best to learn
by doing and you have ample equipment to hand. You can set up IP addressing manually on laptops,
broadband switches and routers that are commonplace around the home. Furthermore, the libraries
used for the ESP32 are common to the native Arduino products so you can apply the knowledge learnt
here to Arduino boards such as the Uno Wi-Fi. A lot of effort will be needed to understand the
communication elements of the Sketches and so the experiments will be kept simple.
Wi-Fi
It will be useful to understand a little about the underlying technology. Wi-Fi provides a means to
interconnect computers and other devices using radio waves and the technology is standardized in
IEEE 802.11. It is commonly used for Local Area Networking (LAN) environments. Local Area
Networks have a small geographical coverage, typically confined to buildings.
Wi‑Fi is a trademark of the Wi-Fi Alliance. This non-profit organization restricts the use of the term
‘Wi-Fi Certified’ to products that successfully complete interoperability certification testing. There are
different versions of the Wi-Fi standards that allow the technology to work over different speeds and
ranges. Wi-Fi most commonly uses the 2.4GHz and 5GHz radio bands. These bands are subdivided into
multiple channels. These frequencies and their low power mean that the radio wave is prone to
absorption from walls and other local objects and so the range tends to be restricted to within a building.
A key element of a Wi-Fi network is the Access Point (AP). This device acts as a hub to which Wi-Fi
enabled clients connect. A client device can be a laptop, TV, Smartphone, or another similar device. The
AP typically provides a wired network connection that can be connected to a fixed network or
broadband router. The concept of and AP is illustrated in Figure 4-1.
DHCP
The Dynamic Host Control Protocol (DHCP) is used to automatically allocate IP addresses to devices
such as Smartphones or Laptops. This makes our life easy when adding a new device to a network.
Without DHCP we would have to manually allocate the IP address. A device such as a broadband router
or Wireless AP will run the DHCP server application. When a new device wants an IP address to connect
to the network, it will broadcast out over the whole network with a DHCP request. The server will
respond and allocate an IP address to that device.
Next, you need to set up the basic parameters for connection to your wireless network. Your network
will have a name. This name is referred to as the SSID (Service Set Identifier). Your network will have
a password too. We define 2 char sets to hold these values. Be sure to substitute you own SSID and
password.
const char* ssid = "your_SSID";
const char* password = "your_password";
All the work is done with the ‘setup’ function as these are all one-time operations. You need to open
the serial monitor and instantiate the connection to your wireless network using the ‘begin’ function
within the ‘WiFi’ class.
Serial.begin(115200);
WiFi.begin(ssid, password); //Try to connect to WiFi
We then hold the code in a loop until the WiFi is connected. We can check connectivity by calling the
‘status’ function and when it equals the pre-defined Enum ‘WL_CONNECTED’, we terminate the loop
and print the status and IP address to the serial monitor.
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}
The IP address is assigned by DHCP, and we can print this address with the code below:
IPAddress ip = WiFi.localIP();
Serial.print ("The IP of this ESP32 is ");
Serial.println (ip);
#include "WiFi.h"
void setup() {
Serial.begin(115200);
void loop() {
//do nothing
}
#include "WiFi.h"
WiFiServer server(80);
String header;
String output33State = "off";
String output32State = "off";
void setup() {
Serial.begin(115200);
pinMode(OUTPUT33, OUTPUT);
pinMode(OUTPUT32, OUTPUT);
//turn off LEDS
digitalWrite(OUTPUT33, LOW);
digitalWrite(OUTPUT32, LOW);
void loop() {
WiFiClient client = server.available(); // Listen for incoming clients
We have already covered the code in the ‘setup’ function. This establishes the WiFi connection and
turns off the LEDS. All the code in the ‘loop’ function is new to us.
We first setup an object of the ‘WiFiClient’ class that instructs the ESP32 to listen for incoming
browser client connections. ‘Server.available()’ is ‘TRUE’ when a client request is incoming. If no
client request is incoming the remaining code in the ‘loop’ function is skipped.
WiFiClient client = server.available(); // Listen for incoming clients
if (client) {
//process client connection
}
When we have an incoming client connection, the data passed will be in text form and so we need to
create a string to hold this data. For this experiment, there will be no data so this variable will be null
in our Sketch but could be used for more complex scenarios. All our actions will be based on the contents
of the header.
String currentLine = "";
We then loop while the client is connected.
while (client.connected()) {
//process client connection
}
We need to keep processing the client request while there are text characters to process in the client
request.
if (client.available()) {
//process client connection
}
The code reads a character from the client connection and prints it to the serial monitor.
char c = client.read(); // read a byte
Serial.write(c); // print it out the serial monitor
We need to create a string by concatenating each of the read characters. The string is called ‘header’
and we will use the resultant string to work out what action needs be taken. The code will read each
character in the client connection until a newline character is read. We use the ‘+=’ operand to form the
string. The ‘+=’ operand takes the value on the left-hand side and appends the value on the right-hand
side. The left-hand side is then set to the new value.
header += c;
If we detect a newline character, we can process the incoming client connection as all characters have
been read.
if (c == '\n') {
//process client connection
}
We check that the ‘currentLine’ string is blank. It will be, as we set it to be blank earlier and so we
can send an HTTP response back to the client from our HTTP server. The response is needed so that
the client can either process the response or wait for the next user input.
if (currentLine.length() == 0) {
//Process HTTP response
}
HTTP responses have a set format and there are specific codes that instruct the browser or client. We
will send a code of 200 that means successful action. You will be familiar with the code of 404 that
means ‘page not found’. We use the ‘println’ function appended to the ‘client’ object to send data
back to the browser.
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
We now move onto the task of processing the ‘header’ string to turn the LEDs on or off. It will be useful
to look at the resultant ‘header’ strings in the serial monitor. We can use the ‘indexOf’ function to
search for a sub-string. If the sub-string text is not present in the string we are searching, then the
function returns a value -1. Therefore, if the value returned is greater than or equal to 0, then we know
that the text is within the substring. We can then toggle the LED based on the results of the substring
search.
if (header.indexOf("GET /33/on") >= 0) {
Serial.println("GPIO 33 on");
output33State = "on";
digitalWrite(OUTPUT33, HIGH);
} else if (header.indexOf("GET /33/off") >= 0) {
Serial.println("GPIO 33 off");
output33State = "off";
digitalWrite(OUTPUT33, LOW);
}
if (header.indexOf("GET /32/on") >= 0) {
Serial.println("GPIO 32 on");
output32State = "on";
digitalWrite(OUTPUT32, HIGH);
} else if (header.indexOf("GET /32/off") >= 0) {
Serial.println("GPIO 32 off");
output32State = "off";
digitalWrite(OUTPUT32, LOW);
}
The next part of the Sketch generates the HTML code for the Webpage and customizes it based on the
current state of the LEDs. Again, we can use the ‘print’ function appended to the ‘client’ object to
pass the Webpage to the browser. There is a real risk here the experiment becomes more about web
pages and web servers than about how to use WiFi to control peripherals connected to the ESP32.
Therefore, the HTML that defines the web page that will be passed to the client browser is kept simple.
I have deliberately not added ‘style’ to the buttons that could be used to format the appearance, color,
and size, but kept things as default.
First, a little about web pages written in HTML. They need a basic format and that is shown below:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>
The elements of the webpage are enclosed by tags. The ‘<>’ brackets open the tag and the ‘</>’ brackets
close the tag. Generally, code is inserted in between these tags. Each webpage needs a HTML
declaration, and the entire page is enclosed in the HTML tag ‘<html>’ and ‘</html>’. We can insert
code in the header section. This could be search engine detectives, code to style page elements such as
text or buttons, even JavaScript can be placed here. In the body section, we place the visual elements of
the webpage such as buttons, sliders, text, forms, and links. Webpages can be written using any text
editor, but Notepad++ does provide some good formatting tools and can be downloaded free here
(https://notepad-plus-plus.org/downloads/). Our HTML code is listed below:
client.println("<!DOCTYPE html><html>");
client.println("<head></head>");
client.println("<body>");
client.println("<h1>ESP32 LED Control</h1>");
// Display current state, and ON/OFF buttons for GPIO 33
client.println("<p>GPIO 33 - State " + output33State + "</p>");
// If the output33 State is off, it displays the ON button
if (output33State == "off") {
client.println("<p><a href=\"/33/on\"><button>ON</button></a></p>");
} else {
client.println("<p><a href=\"/33/off\"><button>OFF</button></a></p>");
}
// Display current state, and ON/OFF buttons for GPIO 32
client.println("<p>GPIO 32 - State " + output32State + "</p>");
// If the output32 State is off, it displays the ON button
if (output32State == "off") {
client.println("<p><a href=\"/32/on\"><button>ON</button></a></p>");
} else {
client.println("<p><a href=\"/32/off\"><button>OFF</button></a></p>");
}
client.println("</body></html>");
To keep this simple, there is no header information although the tags are included. In the body section
we first print a heading ‘ESP32 LED Control’. We then print the current state of GPIO pin 33.
Depending on the state of pin 33, we display an ‘ON’ button if the LED is off and an ‘OFF’ button if the
LED is on. The ‘href’ tag assigns a link to the button and we change the data in this link based on the
state of GPIO pin 33. The ‘/33/on’ or ‘/33/off’ forms our GET method data and is passed to the
server when we click the button. The same code is repeated for GPIO pin 32.
You need to try out the experiment and look at the information in browser URL window when you hover
over the button and look at what is passed by viewing the serial monitor.
Finally, we need to clear the header string and stop the client. The code will then go into a listening
state for the next incoming client request.
header = "";
client.stop();
This is a complex experiment for anybody new to Arduino and coding. Therefore, take time to look at
the video demonstration of this experiment here (https://youtu.be/UruAgdVLPC8).
If you want to enhance the look of your webpage for this experiment, then try adding some Cascading
Style Sheet (CCS) information to format your webpage. There are plenty of resources on the Web to get
you started!
The record is for an employee. A key would be ‘forename’ and the value associated with the key will be
‘Alan’. Notice that only the string values are within quotation marks. That’s pretty much all we need to
know about JSON. We shall now go on to look at how we send a request to the OpenWeatherMap API
and examine what is returned. We will use a standard Web browser to do this. The structure of the API
call is shown below. You should copy this into your Web browser but substitute your location and API
key.
http://api.openweathermap.org/data/2.5/weather?units=metric&q=Edinburgh&appid={your_key}
After coping the URL into your browser, it will return information in JSON format as shown in Figure
4-7.
Current temperature will be under “main” and “temp” and is 14.77C. We will use this data, but you can
see we could build a sophisticated weather station by processing more of the data.
In the Experiment that follows, we will use the ESP32 as a HTTP client as opposed to a server and make
the call to the OpenWeatherMap API. We will parse the result and search for the temperature. We do
have an Arduino JSON library that we can use to make this task easier.
#include "WiFi.h"
#include "Arduino_JSON.h"
//API Elements
const char SERVER[] = "api.openweathermap.org";
const char HOST_STRING[] = "HOST: api.openweathermap.org";
const String API_KEY = "your key here";
const String LOCATION = "Edinburgh"; //swap with your location
const String UNITS = "C";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password); //Try to connect to WiFi
void loop() {
//nothing to do here
}
Listing 4-3: The Sketch to get the Temperature from the API
Listing source: The author
I chose to place all the code within the ‘setup’ function to ensure we only make a single call to the API
each time the Sketch is run.
Make sure you have the libraries added as part of the sketch. The Arduino JSON library really makes
searching the API response easy.
#include "WiFi.h"
#include "Arduino_JSON.h"
We then break down the API call into element parts that make the management of the request easier.
const char SERVER[] = "api.openweathermap.org";
const char HOST_STRING[] = "HOST: api.openweathermap.org";
const String API_KEY = "your key here";
const String LOCATION = "Edinburgh"; //swap with your location
const String UNITS = "C";
In preparing the API request, we need to change the unit value in the API to ‘metric’ or ‘imperial’ based
on whether you set Fahrenheit or Celsius in the API elements. We can make this change with a simple
‘if’ statement and then assemble the API request. We concatenate the API elements to form a single
string called ‘request’.
String apiUnits = "metric";
if (UNITS == "F") {
apiUnits = "imperial";
}
String request = "GET /data/2.5/weather?units=" + apiUnits + "&q=" +
LOCATION + "&appid=" + API_KEY + " HTTP/1.1";
We connect to the remote server using port 80. Port 80 signifies that it is an ‘http’ request. We can echo
our request to the serial monitor for tracking and debug purposes, but we use the ‘println’ function
appended to the ‘client’ object to send the data over the Internet to the remote server. You do need
to stick to the format below, otherwise you will generate a ‘bad request’.
if (client.connect(SERVER, 80)) {
Serial.println ("Sending request..");
Serial.println (request);
Serial.println ("");
client.println (request);
client.println (HOST_STRING);
client.println ("Connection : close");
client.println ();
}
The Sketch processes the data character by character but must discard all characters until the curly
bracket is received ‘{‘. We use the ‘break’ command to exit the perpetual ‘while’ loop when we receive
the first ‘{‘.
while (true) {
char header = client.read();
if (header == '{') break; //break out of loop here
Serial.print (header); //debug to serial monitor
}
Now it is a case of reading the JSON response. The Sketch reads each character and appends each to a
string called ‘jsonData’. The ‘+=’ operator means that the character ‘c’ is added (appended) to the
current value of ‘jsonData’ and the result becomes the new value of ‘jsonData’. This is the first time
I have use the ‘do’ loop in this series of book. A ‘do’ loop must be execute at least once since the
condition for the loop is checked at the end of the pass by the ‘while’ condition.
String jsonData = " {";
do {
char c = client.read(); //read data
jsonData += c;
} while (client.connected());
client.stop();
Finally, the Sketch processes the ‘jsonData’ string. We load the JSON response into an object of the
‘JSONVar’ class. This class is part of the ‘Arduino_JSON.h’ library.
JSONVar apiObject = JSON.parse(jsonData);
Serial.println ("JSON response");
Serial.println (apiObject);
To get the temperature we search for ‘main’ and then ‘temp’ in the JSON response. We define the result
as a ‘double’ since it contains a fractional part. We then print the temperature and units to the serial
monitor.
After running the Sketch, you should see an output like that in Figure 4-12 giving you the I2C address
of the display. If anything, it tells you your wiring is correct!
Figure 4-12: The Serial Monitor showing the I2C Address of the 12864 OLED Display
Image source: The author
You will need to include the ‘wire.h’ library for I2C operations. This is preinstalled into the Arduino
IDE. The library I will be using to control the display is the ‘Adafruit_SSD1306.h’ library. Ensure
you have this installed into your IDE.
We need to reorganize some of the code from Experiment 7 since we will make a call to the API every
minute.
Type in or copy the Sketch as shown in Listing 4-3.
/*
API Access and output to OLED
#include "WiFi.h"
#include "Arduino_JSON.h"
#include "Wire.h"
#include "Adafruit_SSD1306.h"
const char* ssid = "your_ssid";
const char* password = "your-password";
//API Elements
const char SERVER[] = "api.openweathermap.org";
const char HOST_STRING[] = "HOST: api.openweathermap.org";
const String API_KEY = "your API key";
const String LOCATION = "Edinburgh"; //swap with your location
const String UNITS = "C";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password); //Try to connect to WiFi
void getTemperature() {
display.clearDisplay(); //clear display
display.setTextSize(1);
display.setCursor(0, 0); //moves curser
display.print(LOCATION);
//Prepare the API request
String apiUnits = "metric";
if (UNITS == "F") {
apiUnits = "imperial";
}
String request = "GET /data/2.5/weather?units=" + apiUnits + "&q=" +
LOCATION + "&appid=" + API_KEY + " HTTP/1.1";
//Connect to the server and send request
if (client.connect(SERVER, 80)) {
Serial.println ("Sending request..");
Serial.println (request);
Serial.println ("");
client.println (request);
client.println (HOST_STRING);
client.println ("Connection : close");
client.println ();
}
We then define some parameters that are needed for the display setup.
const int SCREEN_WIDTH = 128;
const int SCREEN_HEIGHT = 64;
const int OLED_RESET = -1; //uses Arduino reset button
The next block of code sets up the display and ensures the correct I2C address is used. The code will
loop forever if there is a problem. It is good practice to clear the buffer of the display as you may find it
will print some artifacts before writing actual data. Note that with the 12864 OLED display, actions
such as ‘print’ and ‘clearDisplay’ only act on the display’s buffer. To write to the display you need
to call the ‘display’ function under the ‘Adafruit_SSD1306’ class’s object, e.g.
‘display.display()’. After the display setup, we can call the ‘getTemperature’ function for the
first time.
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for (;;); // Don't proceed, loop forever
}
display.clearDisplay(); //clear display
display.display(); //print blank screen
display.setTextColor(SSD1306_WHITE); // Draw white text
getTemperature(); //get temperature first time round
In the ‘getTemperature’ function, we first print the location onto the display from the top left-hand
corner using the smallest font size. Remember this only writes to the display’s buffer.
display.clearDisplay(); //clear display
display.setTextSize(1);
display.setCursor(0, 0); //moves curser
display.print(LOCATION);
Moving the display curser down a bit and increasing the text size, we print the temperature and units
to the display. We truncate the temperature to 1 decimal place using the ‘, 1’ in the ‘display.print’
function. We finally output the display’s buffer to the screen before repeating every minute.
display.setTextSize(3);
display.setCursor(0, 20); //moves curser
display.print(temperature, 1); //print to 1 decimal place
display.print (UNITS);
display.display();
Summary
In this chapter you were introduced to WiFi concepts and learnt about the organizations that control
WiFi standards. You learnt that the Internet is global network that runs multiple applications such as
the World Wide Web, email, and FTP. You were introduced to some of the technologies that are used
within WiFi networks and the Internet such as IP and DHCP. You learnt how to create a simple Web
server to run on an ESP32 and how to write simple Webpages. You learnt about APIs and how they can
be used to garner real time information from the Web. You also learnt how to use the 12864 OLED
display.
Epilogue
We have come to the end of this part of the journey. If you have followed this series from book 1, you
will be becoming extremely proficient indeed. This subject is more complex than others that I have
covered to date, but I have tried to convey the concepts as clearly and simply as possible. I am aware we
have had to make some generalizations as some of the technologies presented here justify whole books
and are complex. If you are interested in this area, you can use this book as a platform to explore deeper.
It is an important area to explore and is a fundamental component of the Internet of Things.
Here too, you have seen how native Arduino skills can be applied to newer and far more capable
platforms such as the ESP32. I am sure that introducing the ESP32 was to right thing to do for this
Book.
In the subsequent books in the series, we will use our knowledge gained to look at other focus areas and
create ever more challenging, creative and interesting projects. Whatever your goals are, I hope to have
inspired you and helped you some way to achieving those goals.
If you like this book and the series of books, please leave a review on the Amazon website. For the latest
news on other books in the series you can following my Facebook page, Twitter or follow me as an
author on Amazon.
About the Author
Gary Hallberg has over 34 years of experience in the telecommunications and data communications
industries. He started his career working with circuit switched voice and data technologies in PDH and
SDH environments and then moved on to work with early packet switched networks using Frame Relay
and ATM. His career shifted focus to IP routing when the Internet started to grow, designing large scale
service provider networks using leading edge equipment from vendors such as Juniper and Cisco. Gary
attained Cisco Certified Professional status during this time. Presently, he is working for a global
equipment vendor with a focus on Ethernet networks and is at the forefront of network evolution,
providing infrastructures for SD-WAN, Network Functions Virtualization, SDN and 5G backhaul. Gary
has a Bachelor of Engineering degree in electronic engineering and a Master of Philosophy degree in
robotics and manufacturing.