Earlier this week I was having a chat with an AWS Architect I work with. He was talking about some of the things he’s done
with a WiFi enabled Arduino. In turn I mentioned some of the sensors I picked up with the intention of getting them connected
to AWS’s IoT Core service. During this discussion I may have mentioned that I’ve become a bit lazy with my personal projects
and that it was probably gonna take me a while to actually get anything set up. Now, while his reaction probably didn’t have
any ill intentions, it miffed me a little. So this weekend I got off my ass, pulled out an ESP32 board, and attempted to get it
hooked up to IoT Core.
This didn’t go well.
I ended up having a bit more difficulty that I’d like to admit. First up, you need to determine what board you have. I grabbed
the ESP32 board package from Esppresif, but then had to figure out what
the Duinotech ESP32 Main Board
was based off. It’s the ESP32 Dev Module by the way. Once I confirmed I was able to program the device, I ran a couple of the
included examples to confirm I was able to connect to my WiFi.
With the device connected to the WiFi, I went looking for a pre-existing example of connecting it to AWS IoT. Naturally, the
first result in Google was from AWS’s own blog.
Following through the start of this tutorial I was able to manually set up IoT Core and get the ESP32 sending and receiving
messages. However, as I’ve said previously “manual’s for chumps.” The next move was to get everything set up via Terraform.
Handling the certificate creation was a bit of an issue. I could either do it manually and reference the ARN as a Terraform
variable, or I could just have Terraform create it. Having Terraform create it would require exporting the private key as
an output, and ultimately you couldn’t trust the state to be secure. I ended up going this route as it meant I could have
Terraform create the secrets.h file. We simply take in the WiFi details as variables and pull the root CA certificate from
Now, while the Terraform config would deploy correctly and I’d end up with an Arduino project that’d compile and burn, the
ultimate outcome was that nothing was being written or read from IoT Core. After comparing the AWS infrasture to what was built
manually, and even opening up the policy on the certificate, I still couldn’t get it working. So I copied the secrets.h from
the working project into my new one to test, and was able to send and receive messages. This confirmed that the issue was with
the secrets configuration.
This took way to long to work out. In the end it came down to the URL I was using to connect to IoT Core. Compare
xxxxxxxxxxxxx-ats.iot.ap-southeast-2.amazonaws.com and xxxxxxxxxxxxx.iot.ap-southeast-2.amazonaws.com. I was using the
aws_iot_endpoint Terraform data source to retrieve this URL. When you define the data source, you can set an endpoint_type
variable to configure the type of URL generated. What I was originally using was iot:Data when I needed iot:Data-ATS. I
originally missed the ats in the URL and the iot:Data option is the first one the matched my URL without looking too hard.
So ultimately I didn’t end up completing as much as I wanted. It would’ve been nice to have one node sending data and another
receiving it. However, at least I now have a working base to build off of.
The Business Part
First thing we want to do is create our Arduino project. The one I ended up working with is from
TechieSMS. I ended up rearchitecting some of it to help with my
To start off with we want some header stuff
Next we’re gonna add our function to connect to the WiFi:
We want a function to connect to AWS. We’ll use a certificate to authenticate.
We need a callback function to process messages we receive from AWS.
We also want to be able to send messages.
And finally the default Arduino functions set up and run the loop.
With that set up we want to create our secrets template.
Now on to the Terraform. First we want some variables for our WiFi credentials.
We need some details about our AWS environment to create ARNs.
A certificate to authenticate our ESP32 with AWS. We’ll attach a policy to this that allows the Thing to read and write from
This certificate gets attached to a Thing.
And last of all, we want to create our secrets.h file.
With all that in place, our next move is to deploy the Terraform infrastructure. A simple terraform init and
terraform apply should get this done for you. This will create our secrets.h file used by Arduino.
If you now open the Arduino project in the IDE, you can write it to your device. You’ll need to ensure you have the correct
board selected and the required libraries installed.
Once you’ve written to the board, open up the serial console and connect to it. If you reset the board you should see the
Open up the AWS IoT Test console and
subscribe to the # topic. You should start to see the messages coming in.
Flick over to the publish tab, set the topic as example/sub and click publish. You should see the message show up in the
Arduino serial console.
And with that we’re done here. This was a bit more work that I had anticipated. I’m not as convinced about the ESP32 as I used
to be. Maybe an STM32 or something with WiFi, we’ll have to see. I still have that pack of sensors to have a play with.
You can find the source code for this project at GitHub