You are on page 1of 79

Wireless Communications with Arduino and

the ESP32
Book 7 of the Arduino Short Reads Series

Gary Hallberg

North Border Tech Training


First Edition
Copyright © 2021 Gary Hallberg and North Border Tech Training
All reserved. This book or any portion thereof may not be reproduced or used in any manner whatsoever
without the express written permission of the publisher except for the use of brief quotations in a book
review.
First Published, 2021
Contents
About the Arduino Short Reads Series ..................................................................................................... 5
Foreword.................................................................................................................................................... 6
Prerequisites for this Book ........................................................................................................................ 7
Download the Code ................................................................................................................................... 8
Chapter 1: Radio Frequency Communications with Arduino .................................................................. 9
Parts needed for this Chapter ........................................................................................................... 9
What is Radio? ....................................................................................................................................... 9
Data Transfer over Radio Waves .......................................................................................................... 11
Experiment 1: 4-Channel Wireless Control ........................................................................................ 14
Summary .............................................................................................................................................. 19
Chapter 2: The Espressif Systems ESP32 ............................................................................................... 20
Parts needed for this Chapter .............................................................................................................. 20
An Introduction to the ESP32 ............................................................................................................. 20
Arduino or ESP32? .............................................................................................................................. 23
Experiment 2: Enabling the Arduino IDE for the ESP32 and Testing your Environment ................ 23
Summary .............................................................................................................................................. 28
Chapter 3: Bluetooth Communications with the ESP32 ........................................................................ 29
Parts needed for this Chapter .............................................................................................................. 29
What is Bluetooth? .............................................................................................................................. 29
Bluetooth Profiles ................................................................................................................................ 30
The Dabble BTLE App ......................................................................................................................... 30
Experiment 3: Using Dabble to Control the Brightness of an LED .................................................... 33
The Accelerometer ............................................................................................................................... 35
Experiment 4: Smartphone Controlled RGB LED .............................................................................. 36
Summary .............................................................................................................................................. 46
Chapter 4: Wi-Fi and the Internet .......................................................................................................... 47
Parts needed for this Chapter .............................................................................................................. 47
Wi-Fi .................................................................................................................................................... 47
The Internet Protocol .......................................................................................................................... 48
The Internet and the Web.................................................................................................................... 48
DHCP ................................................................................................................................................... 48
Experiment 5: Basic Wi-Fi Connectivity ............................................................................................. 49
A Little more about HTTP ................................................................................................................... 53
Experiment 6: Building a Simple Web Server to Control an LED ...................................................... 53
Application Programming Interfaces .................................................................................................. 60
Experiment 7: API Access with the ESP32 .......................................................................................... 63
The 12864 0.96 Inch OLED Display Module ...................................................................................... 68
Experiment 8: Printing the Temperature to the 12864 OLED Display .............................................. 70
Summary .............................................................................................................................................. 76
Epilogue ................................................................................................................................................... 77
About the Author ..................................................................................................................................... 78
About the Arduino Short Reads Series

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.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 4-channel 315MHz or 433MHz radio controller
• 4 x LEDs
• 4 x 220Ω resistors
• Jumper wires

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.

Data Transfer over Radio Waves


So how do we use radio waves to transfer voice or data information? A pure radio wave is sinusoidal. It
will be generally high in frequency and is called the carrier. We encode information into that wave by
modulating its amplitude or frequency. Modulation is the process of varying these aspects of the carrier
wave by a controlled amount. Receiving equipment can recover the information from the modulated
carrier wave.
Figure 1-2 shows an Amplitude Modulated (AM) radio wave.
Figure 1-2: An Amplitude Modulated Radio Wave
Image source: The author
In this example an audio wave is combined with a high frequency carrier. The amplitude of the carrier
is varied in proportion to the audio wave and can be covered by the receiver.
Figure 1-3 illustrates how the same audio frequency wave can be encoded into a Frequency Modulated
(FM) carrier.
Figure 1-3: A Frequency Modulated Radio Wave
Image source: The author
In this example, the carrier provides a reference frequency. The frequency of this carrier is varied by an
amount proportional to the audio signal to be carried. The receiver can detect the relative change in
frequency and so recover the signal.
How these signals are created by the transmitter and recovered by the receiver, is a complex and lengthy
subject. The subject is beyond the scope of this book where it is enough to make you aware of how
information is carried over radio.
The examples in Figures 1-2 and 1-3 show the principles of audio transmission. The digital radio fob
that we will use for the experiments in this chapter transmits digital information and uses Amplitude
Modulation. Basically, if you receive a signal at the expected frequency for a set amount of time it is
treated as a binary 1. If you do not receive a signal for a set amount of time it is treated as a logic 0.
Figure 1-4 illiterates this concept. You need some error checking information and addressing encoded
into the signal, but in simple terms, that is how it works.
Figure 1-4: A Digital Signal Encoded into a Radio Carrier Wave
Image source: The author

Experiment 1: 4-Channel Wireless Control


In this experiment we will use a basic 4-channel radio system to control 4 Arduino digital outputs. The
radio system used is common, and the generic nature of the device means it does not have a common
part number but is easy to obtain through online retailers. The system in pictured in Figure 1-5 and
operates in the 315MHz band in the Americas and 433MHz in Europe.
Figure 1-5: The 4-Channel Radio System
Image source: The Web (public domain)
In the experiment we will simply turn 4 LEDS on or off with each channel. You may want to consider
using a relay module to switch more powerful equipment, but if this is mains powered, then great care
must be taken, and ensure you have had appropriate training for your safety and the safety of others.
First build the breadboard layout as in Figure 1-6.
Figure 1-6: The Breadboard Layout for the 4-Channel Radio System
Image source: Created with Fritzing
Now type in or copy the Sketch as in Listing 1-1.
/*
Radio Control
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/congenial-
robot/blob/main/LICENSE
*/

//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;

// setup states to toggle LEDs on radio inputs


int led0State = LOW; // the current state of LED0
int lastD0State; // previous state of D0 input
int currentD0State; // current state of D0 input

int led1State = LOW; // the current state of LED1


int lastD1State; // previous state of D1 input
int currentD1State; // current state of D1 input

int led2State = LOW; // the current state of LED2


int lastD2State; // previous state of D2 input
int currentD2State; // current state of D2 input

int led3State = LOW; // the current state of LED3


int lastD3State; // previous state of D3 input
int currentD3State; // current state of D3 input

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

if (lastD0State == HIGH && currentD0State == LOW) {

// toggle state of LED0


led0State = !led0State;
// control LED0 according to the toggled state
digitalWrite(LED0, led0State);
}

//read D1 state and toggle LED1 on state change


lastD1State = currentD1State; // save the last state
currentD1State = digitalRead(D1); // read new state

if (lastD1State == HIGH && currentD1State == LOW) {

// toggle state of LED1


led1State = !led1State;

// control LED1 according to the toggled state


digitalWrite(LED1, led1State);
}

//read D2 state and toggle LED2 on state change


lastD2State = currentD2State; // save the last state
currentD2State = digitalRead(D2); // read new state

if (lastD2State == HIGH && currentD2State == LOW) {

// toggle state of LED2


led2State = !led2State;

// control LED2 according to the toggled state


digitalWrite(LED2, led2State);
}

//read D3 state and toggle LED3 on state change


lastD3State = currentD3State; // save the last state
currentD3State = digitalRead(D3); // read new state

if (lastD3State == HIGH && currentD3State == LOW) {

// toggle state of LED3


led3State = !led3State;

// control LED3 according to the toggled state


digitalWrite(LED3, led3State);
}
}

Listing 1-1: The Sketch to Operate the 4 LEDs


Listing source: The author
After uploading the Sketch, press each of the 4 buttons on the radio transmitter. You will see each LED
toggle for its respective button press. There is not much to review with this code as we are not covering
the basic functions such a ‘digitalRead()’ and ‘digitalWrite()’. What the code does is
continuously scan each state of the 4 digital input pins in turn, and if it detects a state change, the
corresponding LED is toggled.
We do this by checking to see if the last state is ‘HIGH’ and the current state is ‘LOW’ so we only toggle
the LED on the ‘HIGH’ to ‘LOW’ transition. We can then set the last state to the current state otherwise
we will toggle the LED on every pass while the button pressed.
Although this is a simple experiment, we have looked at how to interface motors in previous books and
you could control a fan, or you could connect relays to control higher powered mains devices if you
follow safe practice.
The key takeaway here is that the radio system takes care of all the complex transmission requirements,
and the coding aspect are extremely simple.
You can see a video demonstration of this experiment here (https://youtu.be/GurFFLGVkTw).

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.

Parts needed for this Chapter


1 x ESP32 development Board

An Introduction to the ESP32


Released in 2016, the ESP32 is a modern, powerful, feature rich and low-cost Microcontroller Unit
(MCU). There are considerations that make this MCU a good choice to use going forward in this book.
First, it has integrated WiFi and Bluetooth, second it can be programmed using the Arduino IDE and
makes use of the libraries available for Arduino devices. So, none of the work to date is wasted. Third,
there are few options for Arduino with integrated WiFi. There are some Arduino Nano form factor
devices such as the Arduino MKR WIFI 1010 and the Arduino Uno WiFi Rev2. The latter board is
relatively expensive and turning to an ESP32 with it low cost and extra features is natural and popular
choice.
In summary, the ESP32 supports following features:
• Built in Wi-Fi module that complies with the 802.11 standard
• The Wi-Fi module operates in the 2.4 GHz – 2.5 GHz range
• It supports 3 WiFi modes of operation: 1. Access point. 2. Client. 3. Access point + station
• Dual core 32-bit microprocessor
• Operating voltage of 3.3 V
• Clock frequency from 80 MHz and to 240 MHz
• SRAM memory of 512 KB
• ROM memory of 448 KB
• Supports up to 32Mb of external flash memory
• Maximum current in each pin is 12 mA but 6 mA is recommended
• It has 36 general purpose input / output pins
• General purpose input / output pins can be used for PWM, I2C and SPI functionality
• Bluetooth version 4.2 is supported as well as Bluetooth low energy (BLE)
• Deep sleep current of 2.5 µA
• 10 electrode capacitive touch support
• Hardware supported encryption for AES, ECC, RSA – 4096, SHA2
• On board PCB antenna or IPEX connector which acts as external antenna
• Operating temperature between -40°C to +125°C
Figure 2-1 shows the pin layout for the ESp32 DOIT development board.
Figure 2-1: The Pin Layout for the ESP32 DOIT Development Kit
Image source: The Web (public domain)
Looking at Figure 2-1, you can see that virtually every pin has more than 1 function. This is needed if
we want to pack so much functionality into a small form factor. Therefore, design choices and
compromises need to be made.
A list of important ESP32 peripherals is show below, but we will focus only on the GPIO, Bluetooth,
WiFi and I2C functions.
• 34 Programmable GPIOs
• 18 12-bit ADC Channels
• 2 8-bit DAC Channels
• 16 PWM Channels
• 3 UART Interfaces
• 3 SPI Interfaces
• 2 I2C Interfaces
• 2 I2S Interfaces
• 10 Capacitive Touch Sensing GPIOs
• 16 RTC GPIOs
I will be using the 30 pin ESP32 DOIT development kit. Another popular format for the ESP32 is the
36 pin version of the development kit. From your perspective, it really makes no difference for the
experiments presented in this book.

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.

Figure 2-3: The Arduino Preferences Dialog Box


Image source: The Arduino IDE
In the ‘Settings’ tab, enter the following URL in the ‘Additional Boards Manager URLs’ field.
https://dl.espressif.com/dl/package_esp32_index.json
If you have a URL in this field already, you can separate them with a comma.
Next open the Boards Manager. Go to Tools > Board > Boards Manager…. You need to enter
‘esp32’ in the ‘Type’ field. This will filter the options to ‘esp32’ as in Figure 2-4.

Figure 2-4: The Arduino Boards Manager


Image source: The Arduino IDE
Click on the install button and that is all there is to it. I tend to restart the IDE at this point just to make
sure the new options are available.
It is now time to test the installation.
Power on an ESP32 development board via the micro-USB port. Next ensure that your board is selected
in the IDE via the ‘Boards Manager’ as in Figure 2-5. If not, you will see a list of ESP32 boards to
select from. My board is the ‘DOIT ESP32 DEVKIT V1’.
Figure 2-5: Selecting the ESP32 Development Board
Image source: The Arduino IDE
You will also see that the baud rate of the serial UART is set to 115200bps.
Next load the ‘WiFi scan’ example included with the IDE. The location of this Sketch is indicated in
Figure 2-6.
Figure 2-6: Loading the WiFi Scan Example Sketch
Image source: The Arduino IDE
Simply upload the Sketch to your ESP32 and open the serial monitor. If the ESP32 is working correctly,
you should see an output from the serial monitor like that in Figure 2-7 and you are all set.
Figure 2-7: The Output of the Serial Monitor for the WiFi Scan Sketch
Image source: The author

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.

Parts needed for this Chapter


• 1 x ESP32 Development Board
• Full or half size breadboard
• 1 x LED
• 1 x Common Cathode RGB LED
• 3 x 100Ω resistors
• Jumper wires including Dupont wires
• Android or IOS Smartphone with Dabble App

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.

The Dabble BTLE App


For the next 2 experiments, I plan to use the Dabble Arduino & ESP32 Bluetooth Controller App. It
would be beyond the scope of this book for us to develop a smartphone or laptop app to receive input
from the sensors or control ESP32 outputs. Dabble is built by STEMpedia and is provides a rich ‘out of
the box’ platform for us to explore Bluetooth on Arduino and the ESP32 platform. It provides many
possibilities to build on your knowledge to create your own projects. It is a great STEM resource. The
Dabble website is here (https://thestempedia.com/product/dabble). It is available for both Android
and iPhone.
The current version of Dabble provides the following:
• LED Brightness Control: Control brightness of LEDs
• Terminal: Send and receive text and voice commands over Bluetooth
• Gamepad: Control devices/robot in analog (joystick), digital, and accelerometer mode
• Pin State Monitor: Remotely monitor the live status of devices and debug them
• Motor Control: Control actuators such as DC motors and servos
• Inputs: Provide analog and digital inputs via buttons, knobs and switches
• Phone Sensor: Access different sensors within your Smartphone such as the accelerometer,
gyroscope, proximity sensor, magnetometer, light sensor, sound sensor, GPS, temperature
sensor, and barometer to make projects and conduct experiments
• Camera: Use the camera of your Smartphone for taking photos, record videos, color picking, and
face recognition (coming soon)
• IoT : Log data, publish it on cloud, connect with internet, set notifications, and access data from
APIs like ThingSpeak, OpenWeatherMap, etc (coming soon).
• Oscilloscope: Wirelessly visualize and analyze the input and output signals given to the device
using the oscilloscope module
• Music Tune: Receive commands from the device and play tones, songs or other recorded audio
files on your Smartphone
• Projects (Coming Soon): Make dedicated projects to experience different concepts of the real
world first-hand like home automation, line-followers and robotic arms.
The following boards are supported under Dabble:
• evive
• Arduino Uno
• Arduino Mega
• Arduino Nano
• ESP32
Finally, the following Bluetooth modes are supported by Dabble:
• HC-05, Bluetooth Classic 2.0
• HC-06, Bluetooth Classic 2.0
• HM-10 or AT-09, Bluetooth 4.0 & Bluetooth Low Energy (ESP32 has inbuilt Bluetooth 4.2 &
BLE)
First you will need to download the Dabble app to a smartphone or tablet. On installation it will ask you
to grant permissions. You will need to allow these. Figure 3-1 is an extended screenshot of the Dabble
home page on my Android smartphone.
Figure 3-1: The Dabble Home Screen
Image source: The author
You can see the applications are well organized and easy to access. This makes it easy to control LEDs
and read sensors. All we need to do now is try it.

Experiment 3: Using Dabble to Control the Brightness of an LED


In this experiment we will use the LED Brightness Control module. This experiment will use BLE. First,
build the breadboard layout as in Figure 3-2. The default setting in the Dabble module is to use the built
in LED. However, we will use an external LED. Since the logic is 3.3V, we will use a 100Ω resistor to
limit the current through the LED.

Figure 3-2: The Breadboard Layout to Control the LED


Image source: Created with Fritzing
The Dabble website has ESP32 code available that you can load into the Arduino IDE. The URL below
can be used to locate this code and it is listed for reference in Listing 3-1.
https://thestempedia.com/docs/dabble/led-brightness-control-module/
/*
This is Led brightness control example for ESP32 that uses LED
Brightness Control Module in Dabble app.
This module allows you to control state of pin. You can make pin HIGH
or LOW or can also assign any PWM
value to it.

NOTE: As in esp32 any channel can be configured as a PWM channel hence


any first eight pins controlled by Module
will be treated as PWM and others will be treated as normal digital
pins.

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.

Explore more on: https://thestempedia.com/docs/dabble/getting-started-


with-dabble/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_LEDCONTROL_MODULE
#include <DabbleESP32.h>
unsigned long lasttime=0;
void setup() {
Serial.begin(115200);
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}

void loop() {

/*This function is used to refresh data obtained from smartphone.


Hence calling this function is mandatory in order to get data properly
from your mobile.*/
Dabble.processInput();

//uncomment if you want to check if parameters read correctly


/*Serial.print("Led:");
Serial.print(LedControl.getpinNumber());
Serial.print('\t');
Serial.print("State:"); //0 if led is Off. 1 if led is On.
Serial.print(LedControl.getpinState());
Serial.print('\t');
Serial.print("Brightness:");
Serial.println(LedControl.readBrightness());*/
}

Listing 3-1: The Dabble LED Brightness ESP32 code


Listing source: STEMpedia with comments rearranged for book readability
Upload the Sketch to your Arduino IDE. It will take some time as the Sketch makes heavy use of the
available libraries.
Once the Sketch has uploaded, open the Dabble app and connect to the ESP32. By default, it will have
the name ‘MyEsp32’. The dabble app will enable Bluetooth if needed. You connect to a device by
selecting the ‘plug’ control on the right-hand side of the menu bar. Once connected, select the ‘LED
Brightness Control’ module. In my Sketch, I used GPIO pin 33 so you will need to change the pin to
whatever you used. Once you have done that you can control the LED brightness.
Setup, programming and using this app is simple. If you have tried the Bluetooth experiments from the
previous books in this series, you will have noticed that these too are simple. The point is that the
Bluetooth hardware does all the complex negotiation, setup, and communications itself. The software
libraries make this task even easier, but there are a few key points to note from the Sketch.
First, we load 2 headers. The custom settings can be modified to optimize the code so that it compiles
quicker, but we will leave these as default and the second is a directive to use the LED brightness control
module.
#define CUSTOM_SETTINGS
#define INCLUDE_LEDCONTROL_MODULE

You then need to include the ‘dabble.h’ library.


#include <Dabble.h>
You can change the following line of code to give your ESP32 a Bluetooth device name.
Dabble.begin("Bluetooth_Name");

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.

Experiment 4: Smartphone Controlled RGB LED


The Dabble app has a module that will transmit data from your Smartphone’s accelerometer to the
ESP32. This will use the 3-axis of information to change the color and intensity and an RGB LED. RGB
LEDs were covered in Book 1 of this series (First Steps with Arduino). They consist of 3 LEDs built into
one package: 1 red, 1 green and 1 blue. Therefore, you can ‘mix’ colors by varying the intensity of each
LED. The RGB LED I am using has a common Cathode. This experiment will demonstrate Bluetooth
Classic.
First, build the breadboard layout as shown in Figure 3-4. I have connected the ESP32 to the
breadboard with Dupont jumpers as the ESP32 will not allow you to access the pins on both sides if
inserted in these ‘standard’ breadboards. Dupont wires have a socket at one end and a pin at the other.
Figure 3-4: The Breadboard Layout to Control the RGB LED
Image source: Created with Fritzing
A photograph of my setup is shown in Figure 3-5
Figure 3-5: My Setup for Experiment 4
Image source: The author
Next load the predefined Dabble Sketch to control the Smartphone Accelerometer and upload it to the
ESP32. This is shown in Listing 3-2.
/*
Accelerometer block of Phone sensor module allows you to access your
smartphone's accelerometer values.

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.

Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-


module/
*/
#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>
void setup() {
Serial.begin(115200);
Dabble.begin("MyEsp32"); //set bluetooth name of your device
}

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

Table 3-1. The Dabble Accelerometer Functions


Open the Dabble app and the select ‘Phone Sensor’ module. Enable the accelerometer as shown in
Figure 3-6. You will need to allow permissions to use the accelerometer.

Figure 3-6: The Dabble App Accelerometer Setting


Image source: The author
We need to access the acceleration value for each axis in the next phase of the project. These are shown
on the Smartphone and the serial monitor. Shake the Smartphone in each axis, up and down, side to
side and front to back. A snapshot of values I obtained are shown in Figure 3-7.
Figure 3-7: Acceleration Values for my Smartphone on the Serial Monitor
Image source: The author
I was able to obtain maximum acceleration values of around 18m/s2 in each axis. We need to convert
these acceleration values to a Pulse Width Modulation value for each color of the RGB LED. The red
LED will be controlled by the X axis acceleration, green by the Y axis and blue by the Z axis. I do not
want to shake the Smartphone too hard to change the LED color and intensity, so I chose to limit the
acceleration to -5m/s2 and +5m/s2 in each direction and map these values to the extremes of the PWM
range. You can experiment with your own values. Now copy or type in the Sketch as in Listing 3-3. We
are augmenting the standard Dabble Sketch with our own code to control the RGB LED and we will
focus on these parts.
/*
Accelerometer block of Phone sensor module allows you to access your
smartphone's accelerometer values.

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.

Explore more on: https://thestempedia.com/docs/dabble/phone-sensors-


module/
*/
/*
Additions by Gary Hallberg
Dabble Phone Sensor
Licensed under MIT https://github.com/ghallberg-nbtt/congenial-
robot/blob/main/LICENSE
*/

#define CUSTOM_SETTINGS
#define INCLUDE_SENSOR_MODULE
#include <DabbleESP32.h>

const int FREQ = 5000;


const int RED_LED_CHANNEL = 0;
const int GREEN_LED_CHANNEL = 1;
const int BLUE_LED_CHANNEL = 2;
const int RESOLUTION = 8;

const int RED_LED = 27; //GPIO27 for red LED


const int GREEN_LED = 32; //GPIO32 for green LED
const int BLUE_LED = 33; //GPIO33 for blue LED

void setup() {
Serial.begin(115200);
Dabble.begin("MyEsp32");

// configure LED PWM functionalities


ledcSetup(RED_LED_CHANNEL, FREQ, RESOLUTION);
ledcSetup(GREEN_LED_CHANNEL, FREQ, RESOLUTION);
ledcSetup(BLUE_LED_CHANNEL, FREQ, RESOLUTION);

// attach the channel to the GPIO to be controlled


ledcAttachPin(RED_LED, RED_LED_CHANNEL);
ledcAttachPin(GREEN_LED, GREEN_LED_CHANNEL);
ledcAttachPin(BLUE_LED, BLUE_LED_CHANNEL);

//turn off all LEDS


ledcWrite(RED_LED, 0);
ledcWrite(GREEN_LED, 0);
ledcWrite(BLUE_LED, 0);
}

void loop() {
Dabble.processInput();
print_Accelerometer_data();

float valRed = Sensor.getAccelerometerXaxis();


float valGreen = Sensor.getAccelerometerYaxis();
float valBlue = Sensor.getAccelerometerZaxis();

int valRed_int = (int) valRed; //convert to integer


int valGreen_int = (int) valGreen; //convert to integer
int valBlue_int = (int) valBlue; //convert to integer

valRed_int = map(valRed_int, -5, 5, 0, 255); //convert to PWM value


valGreen_int = map(valGreen_int, -5, 5, 0, 255); //convert to PWM value
valBlue_int = map(valBlue_int, -5, 5, 0, 255); //convert to PWM value

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

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

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();

Listing 3-3: The Sketch to Control the RGB LED


Listing source: The author with library extensions by STEMpedia
Setting up Pulse Width Modulation (PWM) control on the ESP32 is different to how we do this on the
native Arduino boards. Concepts of PWM are covered in Book 1 of this series – ‘First Steps with Arduino’
and I assume you have the knowledge covered in that book.
The ESP32 has 16 independent PWM controllers and these are allocated the numbers from 0 to 15. We
will need to set up 3 PWM channels one for the red, one for the green, and for the blue LEDs. We define
constant values for this.
const int RED_LED_CHANNEL = 0;
const int GREEN_LED_CHANNEL = 1;
const int BLUE_LED_CHANNEL = 2;
We also need to define the PWM frequency. Generally, this is set to 5KHz.
const int FREQ = 5000;

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;

We then assign GPIO pins to each of the LEDs.


const int RED_LED = 27; //GPIO27 for red LED
const int GREEN_LED = 32; //GPIO32 for green LED
const int BLUE_LED = 33; //GPIO33 for blue LED

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);

We initially want to turn off the LEDs so we write a PWM value of 0.


ledcWrite(RED_LED, 0);
ledcWrite(GREEN_LED, 0);
ledcWrite(BLUE_LED, 0);

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();

int valRed_int = (int) valRed; //convert to integer


int valGreen_int = (int) valGreen; //convert to integer
int valBlue_int = (int) valBlue; //convert to integer

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)

• value: the number to map


• fromLow: the lower bound of the value’s current range
• fromHigh: the upper bound of the value’s current range
• toLow: the lower bound of the value’s target range
• toHigh: the upper bound of the value’s target range

The value returned is based on linear relationship between the bounds.


valRed_int = map(valRed_int, -5, 5, 0, 255); //convert to PWM value
valGreen_int = map(valGreen_int, -5, 5, 0, 255); //convert to PWM value
valBlue_int = map(valBlue_int, -5, 5, 0, 255); //convert to PWM value

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.

Parts needed for this Chapter


• 1 x ESP32 Development Board
• Full or half size breadboard
• 1 x 12864 0.96 Inch OLED Display Module
• 2 x LEDs
• 2 x 100Ω resistors
• Jumper wires

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.

Figure 4-1: The Access Point within a Wi-Fi Network


Image source: The author

The Internet Protocol


You can consider Wi-Fi as a transport technology over which individual packets of data will be
forwarded. These packets of data will have different destinations. The Internet Protocol or IP is used to
identify the destinations of these packets. IP is now the ubiquitous addressing protocol and is used in
local area networks, private networks, and the Internet. Therefore, it is extremely important and worth
further study following on from this book. For the introductory level within this book, you only need to
be aware that IP is used to define an address of a network element such as an ESP32 board and is also
used as the source and destination identifier of data packets that traverses a network. There are 2 main
versions of IP. They are IPv4 and IPv6. We will only be using IPv4. You will see IP addresses shown in
what is called the decimal-dot notation. An example of an IP address using this format is show below.
192.168.1.2
A network address is no different in principle to a postal address. It is a means to uniquely identify a
premises. An IP address is used to uniquely identify the network element.

The Internet and the Web


We should discuss the Internet and Internet applications such as the World Wide Web. The terms
World Wide Web (the Web) and the Internet are often interchanged, but they are in fact different
things. The Internet is the underlying IP network that has global reach. The Web is an application that
runs over the Internet. The Web links documents and files together using HyperText Markup Language
(HTML) and transfers data over the Internet using the Hypertext Transfer Protocol (HTTP). Web pages
written in HTML can be accessed using a Web Browser. We will be creating HTML pages for the ESP32
and will also use an embedded Web server within the ESP32. Other applications that run over the
Internet can be broadcast TV, IP Telephony, File Transfer, email amongst others.

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.

Experiment 5: Basic Wi-Fi Connectivity


In this experiment we will simply connect an ESP32 to your Wi-Fi network and take a close look at the
code to do this. The full Listing of the code is shown in Listing 4-1, but first we will review the elements
of the Sketch.
First, you need to install the Arduino ‘WiFi.h’ library.
#include "WiFi.h"

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);

The full Sketch is shown in Listing 4-1.


/*
WiFi Connection
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/congenial-
robot/blob/main/LICENSE
*/

#include "WiFi.h"

const char* ssid = "your_SSID";


const char* password = "your_password";

void setup() {

Serial.begin(115200);

WiFi.begin(ssid, password); //Try to connect to WiFi

// Loop until connection established


while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}

Serial.println("Connected to the WiFi network");


IPAddress ip = WiFi.localIP();
Serial.print ("The IP of this ESP32 is ");
Serial.println (ip);
}

void loop() {
//do nothing
}

Listing 4-1: The Sketch to Connect the ESP32 to a Wireless Network


Listing source: The author
The result from my serial monitor put are shown in Figure 4-2.
Figure 4-2: The Result of the Connection to my Wireless Network
Image source: The author
That is all there is to the experiment, but you can see if the ESP32 is visible on your network by ‘pinging’
it from another device on the same network. You may be using a Windows or Linux laptop to run the
IDE, so you can ping from that. From a Windows laptop you need to open a ‘command prompt’ as
shown in Figure 4-3. Type ‘cmd’ in the search field and press enter. On a Linux machine simply open
a new terminal window.
Figure 4-3: Opening a Command Prompt from a Windows Device
Image source: The author
In the resultant command prompt or terminal window type ‘ping’ followed by the IP address of your
ESP32.
>ping 192.168.1.232
You should get a reply like the one in Figure 4-4:
Figure 4-4: Pinging the ESP32
Image source: The author
Close the command prompt or terminal window when finished.

A Little more about HTTP


We want to go on to control our ESP32 using a Web Browser built into a Smartphone or laptop. Before
we do that, it would be beneficial to understand a little more about Hypertext Transfer Protocol or
HTTP.
You will be familiar with the Hypertext Transfer Protocol. When you access a Web page you will precede
the request with ‘http://’. This informs the browser to use the Hypertext Transfer Protocol and you
want to access a Web page written in HTML. HTTP has a number of ‘methods’ that define how you want
to control data to and from a Web page. For use with Arduino or the ESP32, you need to be familiar
with the GET and POST methods, but mainly the GET method.
The GET method retrieves data from the server. This would typically be a specific web page following
the main URL. If the main URL is ‘www.mysite.com’ and the page you want is ‘products.htm’, you would
enter the following in the browser’s navigation window.
www.mysite.com/products.htm
The GET method data will be ‘/products.htm’.
The POST method is used to send data to the Web server. This information would typically be login
information or other form data.
We will be using the GET method in Experiment 6.

Experiment 6: Building a Simple Web Server to Control an LED


We will now build a simple webserver onto our ESP32 and use a browser to turn LEDs on and off. First
build the Breadboard layout as in Figure 4-5.
Figure 4-5: The Breadboard Layout to Control LEDs
Image source: Created with Fritzing
Now copy or type in the Sketch as in Listing 4-2. We will take a close look later.
/*
Control LEDs from a Browser
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/congenial-
robot/blob/main/LICENSE
*/

#include "WiFi.h"

const char* ssid = "your_ssid";


const char* password = "your_password";
const int OUTPUT33 = 33;
const int OUTPUT32 = 32;

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);

WiFi.begin(ssid, password); //Try to connect to WiFi


// Loop until connection established
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}

Serial.println("Connected to the WiFi network");


IPAddress ip = WiFi.localIP();
Serial.print ("The IP of this ESP32 is ");
Serial.println (ip);
server.begin(); //turn on Web server
}

void loop() {
WiFiClient client = server.available(); // Listen for incoming clients

if (client) { // If a new client connects


Serial.println("New Client.");
String currentLine = "";
while (client.connected()) { // loop while the client is connected
if (client.available()) {
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c; //append each 'c' onot header
if (c == '\n') { // if the byte is a newline character
if (currentLine.length() == 0) {
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if (header.indexOf("GET /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);
}
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head></head>");
client.println("<body>");
client.println("<h1>ESP32 LED Control</h1>");
client.println("<h2>Lights Controller</h2>");

// 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>");
header = "";
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
}
}
}
}

Listing 4-2: The Code to Control LEDs via a Web Browser


Listing source: The author
The code is quite complex, but like all large tasks, we can break it down into smaller chunks to better
understand what is going on.
You need to setup an object of the Web server. We need to allocate a port for the Web service and by
default this will be port 80. I do not want to get into the subject of ports within this book, but if you are
interested then check out the Transmission Control Protocol to TCP. The object will be called ‘server’.
WiFiServer server(80);

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!

Application Programming Interfaces


So far, we have looked at WiFi connections using IP technologies, but these connections have been via
the local network. In this section, will look to see how an Arduino or ESP32 board can be connected to
the Internet to retrieve data from a 3rd party resource. An Application Programming Interface (API) is
a resource that is open to a developer to pull data from a 3rd party and embed that data in a webpage or
use it within our Arduino projects. There are all sorts of APIs that feed news, weather, sports results
etc. Twitter, Facebook and Google Maps offer APIs too. We will use the free OpenWeatherMap API to
display the current temperature at your location. The OpenWeatherMap API can be found at the
following URL:
https://openweathermap.org/api
Bear in mind that most sites that offer API data have free tiers, but the number of times you can access
that API is limited. In the case of OpenWeatherMap, it is 60 access requests per minute. This is ample
as we will only access it once every minute. Also bear in mind that the way you use an API may change
so it is important to keep track of the versions you are using. Therefore, the procedure described here
may be different by the time you read this book, but the general principles will still apply.
First, go to the OpenWeatherMap project website using the URL above. You will need to create an
account. Once you have verified your account following an email, login and navigate to the API tab. You
will see your custom API key. Use this key for your projects. There is no need to create a new key. Figure
4-6 shows the API screen where your key can be found.

Figure 4-6: The OpenWeatherMap API Screen


Image source: The OpenWeatherMap Project with annotations by the author
How do APIs works? As already indicated, they allow a 3rd party to access information, and we will take
a closer look at that later. However, the API provider needs to track the number of calls that are made,
and those calls need to be made from a legitimate user. Some form of authentication is needed. The
unique API key or token is used for this task, so ensure you keep your key secret and do not publish it.
We also need a standard way of expressing the information. The information that an API returns is
organized in what we call ‘key value pairs’. This is typically encoded in XML (eXtensible Markup
Language) for JSON (Java Script Object Notation). Both are human readable, but JSON is easier to
read. Here is an example of how ‘key value pair’ data is organized in JSON.
{
"employee": {
"forename": "Alan",
"surname": "Jackson",
"salary" : 56000,
"married": true
}
}

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.

Figure 4-7: The API Response from OpenWeatherMap.org


Image source: The OpenWeatherMap Project
You will see that the response is human readable, but it is not so easy to read. We can use a JSON
formatter to organize the data in a way we can easily read it. There are many JSON formatters online
and there are also plugins for applications like Notepad++, but I use the following:
https://jsonformatter.org/
Save your initial response to a text file. This JSON formatter allows you to enter the URL directly, but
you should not share your API key. Although this site is safe, get into the habit of keeping your keys
secret. After uploading the file, I got the following response:
{
"coord": {
"lon": -3.1965,
"lat": 55.9521
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}
],
"base": "stations",
"main": {
"temp": 14.77,
"feels_like": 14.55,
"temp_min": 13.6,
"temp_max": 16.14,
"pressure": 1026,
"humidity": 86
},
"visibility": 10000,
"wind": {
"speed": 1.34,
"deg": 180,
"gust": 2.68
},
"clouds": {
"all": 0
},
"dt": 1633716012,
"sys": {
"type": 2,
"id": 2038102,
"country": "GB",
"sunrise": 1633674581,
"sunset": 1633714238
},
"timezone": 3600,
"id": 2650225,
"name": "Edinburgh",
"cod": 200
}

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.

Experiment 7: API Access with the ESP32


In the first part of this experiment, we will access the OpenWeatherMap API and print the temperature
to the serial monitor. In the Experiment 8, we will print the temperature to a 12864 display.
For the first part we do not need to use a breadboard layout. The ESP32 can be powered directly from
the USB connection. Type in or copy the Sketch shown in Listing 4-3.
/*
API Access
Copyright 2021 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/congenial-
robot/blob/main/LICENSE
*/

#include "WiFi.h"
#include "Arduino_JSON.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 key here";
const String LOCATION = "Edinburgh"; //swap with your location
const String UNITS = "C";

WiFiClient client; //ESP32 will be the client

void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password); //Try to connect to WiFi

// Loop until connection established


while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}

Serial.println("Connected to the WiFi network");


IPAddress ip = WiFi.localIP();
Serial.print ("The IP of this ESP32 is ");
Serial.println (ip);
Serial.println();

//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 ();
}

//Now wait for the reply


while (!client.available());
//Discard data until we receive an open bracket '{'
while (true) {
char header = client.read();
if (header == '{') break; //break out of loop here
Serial.print (header); //debug to serial monitor
}

//'{' means JSON data found


String jsonData = " {";
do {
char c = client.read(); //read data
jsonData += c;
} while (client.connected());
client.stop();
//process JSON response
JSONVar apiObject = JSON.parse(jsonData);
Serial.println ("JSON response");
Serial.println (apiObject);
double temperature = (double) apiObject ["main"]["temp"];
Serial.print ("The temperature is ");
Serial.print (temperature);
Serial.println (UNITS);
}

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 needs to wait until we have a reply.


while (!client.available());

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.

double temperature = (double) apiObject ["main"]["temp"];


Serial.print ("The temperature is ");
Serial.print (temperature);
Serial.println (UNITS);

You should have results like mine shown in Figure 4-8.


Figure 4-8: The response from the OpenWeatherMap API
Image source: The author

The 12864 0.96 Inch OLED Display Module


Before we move onto Experiment 8, I want to introduce the 12864 OLED display. We will use this to
print out the temperature and location. We used this display in Book 6 of this series (Arduino Special
Functions), but here is the introduction again for those who have not read that book. I chose this
display, as it is inexpensive, easy to use and has a nice quality output.
The 12864 display module is a 0.96 inch OLED (Organic Light-Emitting Diode) display. It uses the
SSD1306 displays driver that has an I2C interface. It is a high quality, 128 x 64 pixel, self-illuminating
display. Examples of these display modules are pictured in Figure 4-9. Be sure to acquire one with the
PCB header for location into the breadboard.
Figure 4-9; The 12864 0.96 Inch Display Module
Image source: The Web (public domain)
The 12864 OLED display has some advantages to other common displays. First, the I2C interface means
that only 2 pins are needed, and it can share the bus with other devices. Second, it can display both text
and graphics.
The I2C address for the display’s driver chip, the SSD1306 is hardcoded. You should use a prewritten
Sketch to scan for the address after it is connected to your Arduino. The Sketch can be downloaded here
(https://playground.arduino.cc/Main/I2cScanner/) and we will use this in Experiment 8.
As with most sophisticated modules, there is an Arduino library that makes our programming task
much easier, and we will use the ‘Adafruit_SSD1306.h’ library. This library has several functions
that can write directly to the pixels, draw shapes, and write text. There are even websites that offer tools
for you to create bitmap images for this display. When writing to the display you need to specify the
coordinates of the pixel, shape, or text you are writing. Top left is [0, 0], bottom left is [0, 63], top right
is [127, 0] and bottom right is [127, 63] as illustrated in Figure 4-10.
Figure 4-10: The Coordinate Arrangement of the 12864 OLED Display
Image source: The author

Experiment 8: Printing the Temperature to the 12864 OLED Display


The 12864 OLED uses the I2C bus to handle communications with the ESP32. The I2C bus was covered
in a whole chapter of Book 6 (Arduino Special Functions) and so it is beyond the scope here to go into
the detail of how the I2C bus works. It is sufficient to say that it makes connectivity extremely simple.
There are just 2 wires needed for the I2C bus connections (SCL and SDA), 1 for the supply and 1 for
ground. We will use the I2C scanner Sketch to find the address of the OLED display. First, build the
breadboard layout as shown in Figure 4-11.

Figure 4-11: The Breadboard Layout for Experiment 8


Image source: Created with Fritzing
The I2C address for the display’s driver chip, the SSD1306 is hardcoded. You can use a prewritten Sketch
to scan for the address after it is connected to your Arduino. The Sketch can be downloaded here
(https://playground.arduino.cc/Main/I2cScanner/). Copy the ‘i2c_scanner’ Sketch from the Website.
Open the Serial Monitor and upload the Sketch to the ESp32. Ensure you change the serial baud rate
in the Sketch from the default 9600 to 115200.
void setup()
{
Wire.begin();
Serial.begin(115200);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}

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

Copyright 2021 Gary Hallberg


Licensed under MIT https://github.com/ghallberg-nbtt/congenial-
robot/blob/main/LICENSE
*/

#include "WiFi.h"
#include "Arduino_JSON.h"
#include "Wire.h"
#include "Adafruit_SSD1306.h"
const char* ssid = "your_ssid";
const char* password = "your-password";

const int SCREEN_WIDTH = 128;


const int SCREEN_HEIGHT = 64;
const int OLED_RESET = -1; //uses Arduino reset button

//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";

WiFiClient client; //ESP32 will be the client


//Set OLED width and height and attach to I2C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password); //Try to connect to WiFi

// Loop until connection established


while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi..");
}

Serial.println("Connected to the WiFi network");


IPAddress ip = WiFi.localIP();
Serial.print ("The IP of this ESP32 is ");
Serial.println (ip);
Serial.println();

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)


// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
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
}
void loop() {
delay (60000); //delay 1 minute
getTemperature();
}

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 ();
}

//Now wait for the reply


while (!client.available());
//Discard data until we receive an open bracket '{'
while (true) {
char header = client.read();
if (header == '{') break; //break out of loop here
Serial.print (header); //debug to serial monitor
}

//'{' means JSON data found


String jsonData = " {";
do {
char c = client.read(); //read data
jsonData += c;
} while (client.connected());
client.stop();
//process JSON response
JSONVar apiObject = JSON.parse(jsonData);
Serial.println ("JSON response");
Serial.println (apiObject);
double temperature = (double) apiObject ["main"]["temp"];
Serial.print ("The temperature is ");
Serial.print (temperature);
Serial.println (UNITS);
display.setTextSize(3);
display.setCursor(0, 20); //moves curser
display.print(temperature, 1); //print to 1 decimal place
display.print (UNITS);
display.display();
}

Listing 4-3: The Sketch for Experiment 8


Listing source: The author with library contributions from Adafruit and Arduino
Not much to review here. We arranged the code that calls the API into a function so that we can call it
once in the ‘setup’ function and then every minute in the ‘loop’ function. The only new code is
associated with the 12864 OLED display.
We need to add the libraries to control the I2C bus and the 12864 OLED display.
#include "Wire.h"
#include "Adafruit_SSD1306.h"

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();

A photograph of my setup is shown in Figure 4-13.


Figure 4-13: The ESP32 working with the API and 12864 OLED Display
Image source: The author
That completes our look at APIs. I hope you agree they are powerful tools to enhance your Internet
based projects.

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.

You might also like