Most IoT tutorials use something like a Raspberry Pi as the “thing”. The Raspberry Pi is a great device but when it comes to IoT, it feels too much like a computer to me. It has GPIO pins so you can connect different hardware but it runs a full Linux distribution (Raspbian, based on Debian).
I wanted to try a “real” IoT device and decided on an ESP32 from Espressif. The ESP32 is a small device, which has a Wi-Fi & Bluetooth Chip, and plenty of GPIO pins. It supports a range of firmwares including Mongoose OS, Zerynth, ESP Easy, FreeRTOS, and MicroPython.
To make it a true IoT device, I added a hardware button. We are going to connect this ESP32 to AWS IoT and configure the ESP32 so it sends a message to AWS IoT when we press the button.
This lesson is lengthy, especially with all the AWS IoT screenshots. If you get lost, you can use the index below:
Let’s start with AWS. There are three components we need:
The thing is our ESP32 and it requires a certificate for authentication. The policy defines what our thing can do.
Let’s start with the “thing” part. Head over to AWS IoT Core in the services overview:
Under Manage, choose Things:
You’ll see the following screen because you don’t have any things yet:
Select register a thing and choose create a single thing:
We’ll give our thing a name. I’ll call it “esp32”:
You don’t have to select any of the options. Click Next and it will ask you to create a certificate.
The console asks us if we want to create a certificate. We need one so select the Create certificate option:
In the following screen you will see the certificates that were created:
Save the certificate, public key, and private key. We’ll need them later. We’ll also need the root certificates so click on the download button next to A root CA for AWS IoT. This takes you to the X.590 Certificate and AWS IoT page:
Download all the certificates you see here. We’ll need them later.
Now we need to create a policy that defines what our thing is allowed to do. Head over to Secure and select Policies:
The console tells us we don’t have any policies yet. Click on the Create a policy button:
Our policy requires two actions:
The iot:Connect action grants permission to connect to AWS IoT with client id “esp32” and the iot:Publish action restricts the device to publishing on a topic named “esp32”.
Here’s what our actions look like:
Hit the Create button and head back to Secure > Certificates:
In the upper right corner, select Actions:
Now choose the Attach policy option:
Select the “esp32-policy” we created and click on the Attach button:
There is one more thing to do. We need the REST API Endpoint. Go to Manage > Things:
Look for the Rest API Endpoint under Interact:
Write down the REST API Endpoint. In my case it’s:
We’ll need it later when we configure the ESP32. This completes our AWS IoT configuration.
Time to get our hands dirty with the ESP32.
I’m using Windows 10. The first time you connect the ESP32 with the USB cable, your computer won’t recognize the device. Go to Device Manager and you will see an unknown device:
Double-click on the device and click on Update Driver:
Choose the first option to automatically search for the driver:
This won’t take long. Once the driver is downloaded it will also show you the COM port number:
In my case, it’s COM4.
The ESP32 supports different firmwares. My personal favorite is MicroPython. I use Python for many things so it’s great that I can use it for the ESP32 as well.
MicroPython includes a small subset of the Python 3 standard library and is optimized to run on microcontrollers.
I downloaded the latest standard firmware (esp32-20190611-v1.11-44-g8b18cfede.bin) and saved it to my disk. To install the firmware, we need the esptool application. This tool allows us to communicate with the ROM bootloader of the ESP32.
We can install it with pip:
pip install esptool
On Windows, this gets installed in the username folder in the following directory:
First, we need to erase the flash. We do this with the following command:
esptool.py.exe --chip esp32 -p com4 erase_flash esptool.py v2.6 Serial port com4 Connecting....... Chip is ESP32D0WDQ5 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None MAC: 24:0a:c4:c1:0f:50 Uploading stub... Running stub... Stub running... Erasing flash (this may take a while)... Chip erase completed successfully in 8.7s Hard resetting via RTS pin...
Excellent. We now have an empty flash. Let’s install the firmware we just downloaded:
esptool.py.exe --chip esp32 -p com4 write_flash -z 0x1000 c:\users\renemolenaar\Downloads\esp32-20190611-v1.11-44-g8b18cfede.bin esptool.py v2.6 Serial port com4 Connecting.... Chip is ESP32D0WDQ5 (revision 1) Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None MAC: 24:0a:c4:c1:0f:50 Uploading stub... Running stub... Stub running... Configuring flash size... Auto-detected Flash size: 4MB Compressed 1169696 bytes to 731891... Wrote 1169696 bytes (731891 compressed) at 0x00001000 in 64.9 seconds (effective 144.2 kbit/s)... Hash of data verified. Leaving... Hard resetting via RTS pin...
Our ESP32 now has the MicroPython firmware.
Let’s see if we can connect to our ESP32. We can use Putty for this. Enter the COM port number we found in Device Manager and set the speed to 115200:
Once you open the console, you see the following prompt:
Awesome. We now have access to Python on our ESP32!
Before we can connect our ESP32 “thing” to the Internet, we need connectivity. I’ll use the Wi-Fi chip for this. First we need to activate the Wi-Fi chip:
>>> sta_if = network.WLAN(network.STA_IF) I (268050) wifi: wifi driver task: 3ffe2d70, prio:23, stack:3584, core=0 I (285637) wifi: wifi firmware version: 38e2484 I (285637) wifi: config NVS flash: enabled I (285637) wifi: config nano formating: disabled I (285637) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE I (285647) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE I (285677) wifi: Init dynamic tx buffer num: 32 I (285677) wifi: Init data frame dynamic rx buffer num: 32 I (285677) wifi: Init management frame dynamic rx buffer num: 32 I (285687) wifi: Init static rx buffer size: 1600 I (285687) wifi: Init static rx buffer num: 10 I (285697) wifi: Init dynamic rx buffer num: 32
You can verify whether the interface is active or not: