Table of Contents
This post is part three in a three part series of steps to connect Connect NodeMCU to AWS IoT Core. In the last two post we did the following:
- Created a “Thing” in AWS IoT and generated the certificates.
- Converted the certificates and keys to .der format
Now we are ready to configure and program the NodeMCU. There are two parts in this:
- Upload the certificates and keys in NodeMCU flash memory
- Program the NodeMCU
Upload the certificates and keys in NodeMCU SPIFFS memory:
Did you know each ESP8266 allows you to partition the system flash such that you can use it to store both code and support a file system?
This filing system can be used to store infrequently changing data such as; web pages, configurations, sensor calibration data, certificates, etc. Of course, we can do without this step but then we would have to copy the certificates in our code. That will make the certificates a part of every code version and increase the size as well. Instead, we will put the certificates ‘as is’ into the memory and read the certificates in our code.
It has another benefit. The certificates and the code are independent. Changing one does not require us to change another.
To upload the certificates and key to NodeMCU, we will use the ESP8266 sketch data upload tool. The steps to do that are discussed in details in the following articles:
Upload Files to ESP8266 SPIFFS
The above post uses a file called “config.txt” as example. Follow the steps but instead of the config.txt file, place the three .der files created in the previous step.
If you are interested to learn more about how to use the SPIFFS, you can refer to the following post:
The ESP8266 SPIFFS File System – Complete Beginner Guide
We have now successfully uploaded the certificates and the key to the NodeMCU. We will now dive into the program.
Connect NodeMCU to AWS IoT Core to send Data:
We will try sending the following message from the NodeMCU:
{
"Message" : "Hello from NerdyElectronics.com" - 0
}
The zero in the end of the message is actually a count variable and we will update the count every time we send the message. We will send the message at every 5 seconds. So, we should receive the messages with the values 0-1-2-3…
We will need three information to edit in the program:
- The Wifi SSID or name
- The Wifi password
- The AWS endpoint of the thing which we created
To retrieve the AWS endpoint, login into the AWS Console and open the IoT core Services. In the AWS IoT screen, click on Manage > Things from the left navigation panel. Open the thing that you created and select “Interact“. There you can see the endpoint.
Program to Connect NodeMCU to AWS IoT Core and send data:
/****************************************************************************************** Connect NodeMCU to AWS IoT Core. Publish Messages from NodeMCU to the Core Tutorial by https://nerdyelectronics.com : 1) AWS IoT - Create a Thing https://nerdyelectronics.com/iot/how-to-create-a-thing-in-aws-iot/ : 2) Convert Certificates from .pem to .der format https://nerdyelectronics.com/iot/how-to-convert-certificates-from-pem-to-der-format/ : 3) Connect NodeMCU to AWS IoT Core https://nerdyelectronics.com/iot/how-to-connect-nodemcu-to-aws-iot-core/ : *********************************************************************************************/ #include "FS.h" #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <NTPClient.h> #include <WiFiUdp.h> // Update these with values suitable for your network. const char* ssid = "XXXXXXXXX"; //Edit this line and put in your Wifi Name const char* password = "XXXXXXXXXXXXXX"; //Edit this line and put in your Wifi Password int count = 0; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org"); const char* AWS_endpoint = "XXXXXXXXXXX-ats.iot.us-east-2.amazonaws.com"; // Edit your AWS Endpoint here void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); } WiFiClientSecure espClient; PubSubClient client(AWS_endpoint, 8883, callback, espClient); //set MQTT port number to 8883 as per //standard long lastMsg = 0; char msg[50]; //buffer to hold the message to be published int value = 0; void setup_wifi() { delay(10); // We start by connecting to a WiFi network espClient.setBufferSizes(512, 512); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); timeClient.begin(); while (!timeClient.update()) { timeClient.forceUpdate(); } espClient.setX509Time(timeClient.getEpochTime()); } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect("ESPthing")) { Serial.println("connected"); // Once connected, publish an announcement... client.publish("outTopic", "hello world"); // ... and resubscribe client.subscribe("inTopic"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); char buf[256]; espClient.getLastSSLError(buf, 256); Serial.print("WiFiClientSecure SSL error: "); Serial.println(buf); // Wait 5 seconds before retrying delay(5000); } } } void setup() { Serial.begin(115200); Serial.setDebugOutput(true); // initialize digital pin LED_BUILTIN as an output. pinMode(LED_BUILTIN, OUTPUT); setup_wifi(); delay(1000); if (!SPIFFS.begin()) { Serial.println("Failed to mount file system"); return; } Serial.print("Heap: "); Serial.println(ESP.getFreeHeap()); // Load certificate file File cert = SPIFFS.open("/cert.der", "r"); //replace cert.crt with your uploaded file name if (!cert) { Serial.println("Failed to open cert file"); } else Serial.println("Successfully opened cert file"); delay(1000); if (espClient.loadCertificate(cert)) // add the thing certificate to the client Serial.println("cert loaded"); else Serial.println("cert not loaded"); // Load private key file File private_key = SPIFFS.open("/private.der", "r"); //replace private with your uploaded file name if (!private_key) { Serial.println("Failed to open private cert file"); } else Serial.println("Successfully opened private cert file"); delay(1000); if (espClient.loadPrivateKey(private_key)) // add the private key to the client Serial.println("private key loaded"); else Serial.println("private key not loaded"); // Load CA file File ca = SPIFFS.open("/ca.der", "r"); //replace ca with your uploaded file name if (!ca) { Serial.println("Failed to open ca "); } else Serial.println("Successfully opened open ca"); delay(1000); if (espClient.loadCACert(ca)) // add the AWS root certificate to the client Serial.println("ca loaded"); else Serial.println("ca failed"); Serial.print("Heap: "); Serial.println(ESP.getFreeHeap()); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); long now = millis(); if (now-lastMsg > 5000) { lastMsg = now; count++; //create the message to be sent snprintf (msg, 75, "{\"Message\": \"Hello from NerdyElectronics.com\" - %d}", count); Serial.print("Publish message: "); Serial.println(msg); // publish messages to the topic "outTopic" client.publish("outTopic", msg); Serial.print("Heap: "); Serial.println(ESP.getFreeHeap()); //Low heap can cause problems } digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) delay(100); // wait for a second digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW delay(100); // wait for a second }
You can download the code from here.
Do make sure to update the following lines:
- Line number 23 –
const
char
* ssid =
"XXXXXXXXX"
;
– Add your Wifi Name here - Line number 24 –
const
char
* password =
"XXXXXXXXXXXXXx"
;
Add your Wifi password here - Line number 29 –
const
char
* AWS_endpoint =
"XXXXXXXXXXX-ats.iot.us-east-2.amazonaws.com"
;
Add your AWS Endpoint here. - Line number 193 –
snprintf (msg, 75,
"{\"Message\": \"Hello from NerdyElectronics.com\" - %d}"
, count);
This is the line where we create the message which we want to send. - Line number 198 –
client.publish(
"outTopic"
, msg);
– In this line we publish the message we created in line 193. We publish it to the topic “outTopic”. If you want to publish the message to some other topic, edit the topic name here.
Check received messages in AWS IoT – Subscribe to Topic
So, we have started transmitting. Let us now check in the AWS IoT Core if we are receiving them.
In the AWS IoT Core screen, click on “Test” in the left Navigation panel. Then click on “Subscribe to a topic“. Add the topic name “outTopic” or the topic name that you have mentioned and click on “Subscribe to topic”
We should start seeing the messages sent by our NodeMCU in AWS now.
Send Message from AWS IoT – Publish to Topic
We will now send messages from AWS IoT console to our NodeMCU
In the AWS IoT “Test” where we subscribed to topic, click on “Publish to a topic“. Add the topic name “inTopic“. This is the topic which the NodeMCU subscribes to.
client.subscribe("inTopic");
Now, when you click on “Publish to topic“, we can see the message in the the Arduino Serial Monitor:
That’s it. We have successfully communicated with AWS.
I hope you have enjoyed doing this. Please do let me know in the comments what you think.
Vivek is a Senior Embedded Innovation Specialist. He has been working on Embedded Systems for the past 10 years. He loves to share his knowledge and train those who are interested. Nerdyelectronics.com was started out of this interest.
Simply awesome. Nicely explained with detailed steps!
very clear and crisp, to the point info. please, create more aws iot services article.
Will do.