I’ve been working for some time now with IOT and I’ve worked extensively with the Esp8266 chip just because I’m testing a lot of stuff and don’t want to spend a lot of money in it.
You can get these small WiFi chips at very reasonable prices like these on Aliexpress for example. The main reason beside their price about why Esp8266 are so interesting is because along with their WiFi capabilities, they are fully programmable like arduinos and there are countless of libraries available for them, not the least the set of libraries allowing you to connect to Azure IOT Hub. That’s what we are going to do in this post.
Pre-requisite : To make this work you need to have an Azure IOT hub ready. If you don’t have one already, you can check this Microsoft Docs to create one : https://docs.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-dotnet
Remarks : In this tutorial I will be using Visual Studio Code but you can use Arduino IDE directly if you want. The main reason I’m using Visual Studio Code is because of the dark theme (I just love it).
Starting blocks
If you’re not already familiar with working with arduinos, you need to know that a typical Arduino program contains two main methods : setup() and loop().
The setup() method is executed once when the device starts up. The loop() method is executed continuously in an infinite loop until the device stops (by turning it off yourself or a power failure, etc…)
void setup() { } void loop() { }
The Esp8266 can be programmed as any Arduino and to do so, you need first the Arduino IDE that you can download here : https://www.arduino.cc/en/Main/Software.
You can find here everything you need to configure the Arduino IDE to program the Esp8266 : https://github.com/esp8266/Arduino.
Once this is done, you can, if you want to use the same environment as I do in this post, download Visual Studio Code here : https://code.visualstudio.com/
You can then download the Arduino extension in the Visual Studio Code and configuring accordingly (going into settings to specify the path to the Arduino IDE) to make this work.
Coding
In this tutorial, we’re not going to use any sensor, we’re just going to send dummy data as the aim here is to help you connect the Esp8266 to Azure IOT Hub so whether or not we have a sensor is irrelevant.
Libraries
The first thing we need are the libraries. Without them, you can either code everything by yourself and reinvent the wheel (which can be very fulfilling I can imagine), or you can just prepare yourself to give up. Whatever you decide, just use the libraries.
You need to go to the library manager and download the following :
- AzureIotHub
- AzureIotUtility
- AzureIotProtocol_MQTT
- ESP8266WiFi
Now it is important to note that you need to include them in your app file in the following order
#include <AzureIoTHub.h> #include <AzureIoTUtility.h> #include <AzureIoTProtocol_MQTT.h> #include "ESP8266WiFi.h"
or you will have some weird error like this one :
AzureIoTProtocol_MQTT\src/AzureIoTProtocol_MQTT.h:7:39: fatal error: azure_umqtt_c/mqtt_client.h: No such file or directory #include "azure_umqtt_c/mqtt_client.h" ^ compilation terminated. exit status 1 [Error] Exit with code=1
And by doing so, you will be saving a few hours of mad, non-sense debugging. Trust me, I’ve been there.
Init WiFi
Now is the time to really start to code. The following code snipper initializes the WiFi connection.
void initWifi() { Serial.println("Initialising wifi connection"); Serial.print("Connecting to WiFi network "); WiFi.mode(WIFI_STA); WiFi.begin("yourNetworkSsid", "yourNetworkPassword"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print('.'); } Serial.println(""); Serial.println("WIFI connection"); Serial.print("IP Address : "); Serial.print(WiFi.localIP()); }
This piece of code uses the ESP8266WIFI library.
- WiFi.mode(WIFI_STA) : sets the WiFi mode to client. The other possible modes are WIFI_AP, WIFI_STA, WIFI_AP_STA or WIFI_OFF (see http://esp8266.github.io/Arduino/versions/2.1.0-rc1/doc/libraries.html).
- WiFi.begin(“yourNetworkSsid”, “yourNetworkPassword”) : Tells the Esp8266 to try connecting to the network specified in parameter 1 with the password specified in parameter 2.
- while (WiFi.status() != WL_CONNECTED) : This starts a loop that will exist when the Esp8266 is connected to the specified network or until a timeout occurs. Note that there’s a delay in the loop. In my opinion it’s good practice to add a delay of a few milliseconds in loops that include connecting to something as it gives the time for the process to complete or gracefully exit before starting the process again.
Init Time
I would like you to be extra careful now, because this is a piece of code that eluded me and it gave me a few headaches.
Before connecting to Azure IOT Hub you need to properly init the time on your Esp8266 as it doesn’t have an internal clock and the time needs to be right or you’ll always get an Access Denied error when trying to connect.
void initTime() { time_t epochTime; configTime(0, 0, "pool.ntp.org", "time.nist.gov"); while (true) { epochTime = time(NULL); if (epochTime == 0) { Serial.println("Fetching NTP epoch time failed! Waiting 2 seconds to retry."); delay(2000); } else { Serial.printf("Fetched NTP epoch time is: %lu.\r\n", epochTime); break; } } }
The code is self-explanatory. The only important thing here is that we’re trying to connect to either of the two time server specified in the configTime method parameters, namely pool.ntp.or and time.nist.gov. This worked for me but feel free to use your favourite time server instead, it should work just fine.
Using the Azure IOT Hub libraries
This is where it gets interesting (if it wasn’t already the case)
To connect to the IOT Hub we first need to a IOTHUB_CLIENT_LL_HANDLE like so :
IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle;
Then we need to initialize the client
iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(IOT_HUB_CONNECTION_STRING, MQTT_Protocol);
The IOT_HUB_CONNECTION_STRING represents the connection string to your Azure IOT Hub device that you configured. You can find it in your Azure Portal. We need to have a message to send.
We’re building here a dummy one.
String JSONMessage = "{\"Temperature\":25, \"Humidity\":50}";
Then we create a IOTHUB_MESSAGE_HANDLE
IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromString(JSONMessage.c_str());
In case there’s an issue with the messageHandle we do this test
if (messageHandle == NULL) { Serial.println("Unable to create a new IoTHubMessage."); } else { if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void *)(uintptr_t)messageTrackingId) != IOTHUB_CLIENT_OK) { Serial.println("The client hasn't accepted the message"); } else { (void)printf(" Message Id: %u Sent.\r\n", messageTrackingId); IoTHubMessage_Destroy(messageHandle); }
In the else scope, we add the message in the queue of event to send. If there are not problem during this we can destroy the messageHandle. Always keep in mind resources are extremely limited on a Esp8266.
The IotHubClient_LL_SendEventAsync accepts 4 parameters :
- iotHubClientHandle : the client created before.
- messageHandle : the handle of the message we want to send
- sendCallback : a void method that will be executed when the iotHubClientHandle actually sent the event to the Azure IOT Hub.
- (void *)(uintptr_t)messageTrackingId : [Optional] I haven’t looked up what is this about.
Now we’re ready to process the sending of the events :
IOTHUB_CLIENT_STATUS status; while ((IoTHubClient_LL_GetSendStatus(iotHubClientHandle, &status) == IOTHUB_CLIENT_OK) && status == IOTHUB_CLIENT_SEND_STATUS_BUSY) { Serial.println("In the sending loop"); Serial.println(IOTHUB_CLIENT_STATUSStrings(status)); IoTHubClient_LL_DoWork(iotHubClientHandle); ThreadAPI_Sleep(10000); } IoTHubClient_LL_Destroy(iotHubClientHandle); } } else { Serial.println("Could not create the iot hub client handler"); }
And that’s it. Now when you upload this code to your Esp8266 you should see events being sent to your Azure IOT Hub. Mind that if you need to set up a custom message routing or a client reading the Azure IOT Hub events.
Nice work a simply and usefull post, congrats!! and thanks this is exactly what i looking for.
In some cases i encounter this error and i cant solve it:
‘iotHubClientHandle’ does not name a type
Hi,
Thank for your comment.
Could you please send me the exact error message you receive so I can maybe try to help you.
Hi again, sorry for the late reply; i already solve it, i was declaring the handle out of the correct scope
And can you post a complete snippet of this code?