# Build a room temperature monitor using Azure and Arduino Nano - Part 1

In this series of tutorials, we will build a room-temperature monitor with the help of Arduino and Azure. For measuring the temperature, we will use a temperature sensor connected to the Arduino nano board. Then, Arduino will periodically send the temperature values to Azure IoT Hub using the azure sdk c for Arduino and the mqtt protocol. Finally, we will transform this stream of data using Azure stream analytics and create some nice dashboards using Azure Data Explorer, also deployed in Azure.

We will start with only one temperature sensor to simplify the process, later I will add also a light sensor to have more data to play with, but feel free to adapt the code to add more/new sensors. Or even use some mocked data if you don't have any sensor available.

By the conclusion of this tutorial, the resulting solution should appear similar to the following:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684524295589/39fbecf4-2dc7-4267-8a61-846a9b53194e.jpeg align="center")

<mark>All the required Arduino code discussed in this tutorial can be found in this GitHub repository.</mark>

## Required Hardware

* Arduino, I used the [nano RP2040](https://docs.Arduino.cc/hardware/nano-rp2040-connect)
    
* [Grove Shield](https://www.seeedstudio.com/Grove-Shield-for-Arduino-Nano-p-4112.html) - Optional
    
* [Temperature sensor](https://www.seeedstudio.com/Grove-Temperature-Sensor.html) - Or any other sensor
    
* Azure account - All the necessary tools should have no cost under the free tier
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684524370175/c3cc45cb-aab7-4aee-b694-17962fc3c1f3.jpeg align="center")

> **Important information if you are using the Arduino nano RP2040 with the grove shield**
> 
> As you can check [here](https://forum.seeedstudio.com/t/grove-shield-for-Arduino-nano-v1-0-can-it-be-used-with-a-nano-rp2040/258699/4) there is an incompatibility between the grove shield and the Arduino nano RP2040. The Grove shield was designed for the Arduino nano 33 (and its variants), although being very similar, the pinout is not the same on the nano RP2040. The RP2040 only has one RESET PIN, the other is used for the REC (BOOTSELECT). The GROVE shield has these two pins connected, on the nano 33 it works correctly because they have the same function. But if you try to use this shield on the RP2040 you won't be able to connect the Arduino to the pc, it won't be recognized as a device. So as suggested on the previous link you can just cut the grove shield connection between the 2 RESET pins, you don't have to drill, a sharp knife is enough to break the link.
> 
> [Nano 33 Pinout](https://content.Arduino.cc/assets/Pinout-NANOble_latest.pdf)
> 
> [Nano RP2040](https://docs.Arduino.cc/static/97fbbd7b8b0d0f12efd7fc3e3cd5de35/ABX00053-full-pinout.pdf)
> 
> [Grove shield remove RESET connection link](images/grove_shield_nano_rp2040.jpg)

## Hardware setup

If you are using the grove shield the connections are quite easy to do. Just put the Arduino in the grove shield and connect it to the USB port. Then connect the sensor using the grove cable to the A0 pin.  
If you aren't using the grove shield, or if you are using another sensor that doesn't have the grove connection, just connect the sensor VCC and GND port to the corresponding Arduino ports and the signal cable to the A0 pin.

> ⚠️The code I provide in this tutorial is adapted to the seedstudio temperature sensor. If you use another sensor you may have to adapt the code to correctly read its value.

> ⚠️ Don't forget to move the VCC switch of the grove shield to 3.3V if you are using a Arduino nano (all models).

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684524915726/2b07f644-2561-4eb7-ad70-a47edd4b36e9.jpeg align="center")

## Some theory before writing code

This section provides a concise explanation of the mathematics behind the code that we will implement later. As the primary focus of this tutorial is Azure IoT, understanding this section isn't crucial; you can skip directly to the next section.

However, if you're interested in learning the details of the sensor readings implementation, please continue reading this section.

### Thermistors

The temperature sensor I'm using uses a thermistor to read the ambient temperature. A thermistor is a resistor whose resistance is dependent on the temperature. By measuring the resistance we can calculate the temperature by approximation using one of two formulas, [beta equations](https://www.ametherm.com/thermistor/ntc-thermistor-beta) or the most accurate [Steinhart and Hart Equation](https://www.ametherm.com/thermistor/ntc-thermistors-steinhart-and-hart-equation)

Despite being more accurate, the Steinhart and Hart Equation is a bit more complex to implement. Since the objective of this tutorial isn't to have the most accurate temperature measuring I'll implement the Beta equation. We can find the Beta equation on page 6 of the thermistor [datasheet](https://files.seeedstudio.com/wiki/Grove-Temperature_Sensor_V1.2/res/NCP18WF104F03RC.pdf). All of the constants required to complete the formula are specified on the datasheet.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525075220/71a2db14-279f-4c3b-9965-9ee045ea0856.jpeg align="center")

| Variable |  |
| --- | --- |
| T | The calculated temperature in **Kelvin** - The objective |
| T0 | Reference temperature - 25 Celsius in Kelvin - 298.15K - Defined in the datasheet |
| R<sub>T</sub> | Measured thermistor resistance (ohm), calculated using the voltage divider circuit. **Check next section** |
| R<sub>T0</sub> | Resistance at 25C - (100K ohm) - Datasheet page 11 |
| β | 4250 - Datasheet page 11 |

In the next section, we will see how we can calculate the RT value.

### Measure the thermistor resistance

From the previous equation, only the Rt value is missing. This Rt represents the measured thermistor resistance. Calling the analogRead() function reads the voltage on pin A0 and converts it to a digital value with 10-bit resolution, but this isn't precisely what we need. Keep in mind that we require the resistance value (ohms) rather than the voltage (V) measured on pin A0.

Upon examining the [temperature sensor's internal schematic](https://files.seeedstudio.com/wiki/Grove-Temperature_Sensor_V1.2/res/Grove_-_Temperature_sensor_v1.1.pdf), we can observe that it features a [voltage divider circuit](https://ohmslawcalculator.com/voltage-divider-calculator). With the value of a known resistance (100k Ohm, R1 in the schematic) and the voltage measured at the A0 pin (SIG in the schematic), we can determine the unknown resistance. In this instance, it is the thermistor's resistance, which is the final missing component needed for the temperature calculation formula.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525281858/5e162c3b-db94-47b9-82ce-20ccd250f202.jpeg align="center")

After some math we will end up with the following formula to calculate the value of the resistance of the thermistor:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525303584/8b396644-caec-4bca-b451-899c18f2a79f.jpeg align="center")

| Variable |  |
| --- | --- |
| Rthermistor == R2 | Resistance(ohm) of the thermistor, R2 in the schema |
| Vcc | Arduino Vcc, 3.3V for the nano, 5V for the uno |
| R1 | 100K ohm - R1 in the schema, the known resistor of the voltage divider circuit |
| V | Voltage measured on the A0 pin - In the schema it is the voltage measured between SIG and GND. Calculated using the value returned by the analogRead function (formula 2) |
| analogReadValue | The value returned by the analogRead function. An Integer between 0 and 1023 representing the voltage read on pin A0 after the analog to digital conversion. |

With the formula to obtain the resistance of the thermistor, we can implement the beta equation in the Arduino to get the temperature read by the sensor.

## Azure Configuration

Before proceeding, we have to create the necessary resources on Azure. For this project we will need the following resources:

* Resource group
    
* Iot Hub
    
* Device
    

To create these resources we can either use azure cli or the web interface, in this tutorial I'll mainly use the web version but I'll document the Az cli commands whenever possible.

### Create a resource group

Navigate to Azure resources group page and create a new resource group.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525348326/78674b77-dc14-47cd-8935-8570df46a726.jpeg align="center")

`az group create --location eastus --resource-group Arduino-iot-demo`

### Create IoT Hub

Navigate to Azure IoT Hub page and create a new Hub.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525387302/9a78834c-4abc-4881-803c-3f7947ac3f1b.jpeg align="center")

To avoid costs you can choose the Free tier during the hub creation.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525404537/ac549fad-35aa-491d-9595-773ba75739ad.jpeg align="center")

`az iot hub create --name iot-hub-name --resource-group Arduino-iot-demo --sku F1 --partition-count 2`

### Create Device

After the Hub is created we must add a new device to it. To do that you should navigate to the newly created hub page, and click on the "Devices" tab.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525427956/b23a0aa2-94af-44b8-b69c-5b3e35077a5d.jpeg align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525433282/097f2a8d-a10a-4693-9bd8-730e015cfa8f.jpeg align="center")

#### Get keys to generate the SAS token

To authenticate on Azure Iot the device will need to generate a SAS token, we will see the details later in the code, but for now, you should copy and save the device's primary key.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525459712/9fcc02f6-4281-4744-8ef7-07420c94b96b.jpeg align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525469258/425f3384-38e0-4de5-b2db-7eb3d16fc5e7.jpeg align="center")

## Configure Arduino root trusted certificates

> ***⚠️***Arduino nano rp2040 stores the trusted root certificates on the wifi module hardware. You must install the Azure IoT Hub Root certificate in the wifi module.
> 
> If you fail to do so you may get the following error: MQTT connecting ... \[ERROR\] failed, status code =-2. Trying again in 5 seconds. {{&lt; /admonition &gt;}} {{&lt; admonition type=warning title="Important" &gt;}} These instructions only apply to the Arduinos equipped with NINA wifi modules, for example the nano rp2040. If you want to run this code on another hardware please verify how the root certificates are configured before continuing.

> ***⚠️*IoT Hub root certificate migration after 2023**
> 
> Microsoft will change the Root certificate of all IoT Hubs domains in 2023. Currently, the root certificate is "Baltimore CyberTrust Root", after 2023 it will be "DigiCert Global Root G2". This means that you'll have to repeat this step after the migration, otherwise, your code will stop working.
> 
> However, if you want to keep your project running without issues after the migration you can already load the new root certificate. You can fetch it from this domain [g2cert.azure-devices.net](http://g2cert.azure-devices.net).
> 
> More info [here](https://techcommunity.microsoft.com/t5/internet-of-things-blog/azure-iot-tls-critical-changes-are-almost-here-and-why-you/ba-p/2393169).

Contrary to a typical browser, the Arduino wifi module can't store hundred of Root certificates, you can only store around 10 certificates. So you'll have to pick them wisely according to your project needs. In this case, we only want to connect to azure IoT Hub, so it is enough to add the root certificate of Iot Hub certificate chain.

To install/delete root certificates you have to use the WiFiNina firmware update [tool](https://docs.Arduino.cc/tutorials/generic/WiFiNINAFirmwareUpdater). It is bundled by default in Arduino IDE.

1. Open the firmware update sketch  
    To run the firmware update tool you'll have to upload the FirmwareUpdate sketch to the Arduino.
    
2. ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525644768/f1e7ff2e-c6af-44d7-94f2-3552b412c4c4.jpeg align="center")
    
3. Upload the FirmwareUpdater sketch to Arduino
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525659254/f8dbb3a8-6ce9-4691-9359-0bdfc5aa651c.jpeg align="center")
    
4. Open the firmware update tool
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525672103/c742177b-423a-4e54-a079-d7df0923d4f8.jpeg align="center")
    
5. Find the hostname associated with your IoT Hub
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525683546/fac1bdb0-918e-42a6-887f-da8f43374594.jpeg align="center")
    
6. Install the Azure Iot Hub root certificate on the wifi module  
    You don't need to download the certificate to your machine. The firmware update tool fetches the certificate associated with the hostname and installs it in the wifi module.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525694372/5323fabc-259a-4659-957b-2f2e99616b0c.jpeg align="center")
    

## Code Implementation

In this tutorial we aren't going to reinvent the wheel, so we will use some libraries already created specifically for Arduino.

| Library | Location |
| --- | --- |
| Azure SDK for Embedded C - Arduino port | [https://www.Arduino.cc/reference/en/libraries/azure-sdk-for-c/](https://www.Arduino.cc/reference/en/libraries/azure-sdk-for-c/) |
| WiFiNINA | [https://www.Arduino.cc/reference/en/libraries/wifinina/](https://www.Arduino.cc/reference/en/libraries/wifinina/) |
| Arduino Client for MQTT | [https://www.Arduino.cc/reference/en/libraries/pubsubclient/](https://www.Arduino.cc/reference/en/libraries/pubsubclient/) |

All of these libraries can easily be installed using the Arduino Ide library manager. You should be able to find all of them on the Arduino IDE library manager.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525734126/71d10208-ee7c-4d9e-96e4-03e95dbd31e7.jpeg align="center")

> This code cannot be used on other Arduino boards without modifications. The first limitation is the Wifi module. I am explicitly using the WifiNina library, so if you have different hardware for the network interface, you must adapt your code to use the corresponding library. You can find some code samples for different hardware [here](https://github.com/Azure/azure-sdk-for-c-Arduino/tree/main/examples).
> 
> Additionally, I have used some mbed core modules. I am unsure if all boards have the mbed core included or not. I believe it only applies to the Nano 33 boards and the RP2040.

The code to read the temperature from the sensor and upload it to Azure is available in the [Github repo](https://github.com/hugo-ma-alves/Arduino-nanorp2040-azure-iot-hub-demo). Before uploading it to Arduino you must open the secrets.h file and change the variables accordingly. This file defines the values that are specific to your environment, for example, your wifi ssid and password and the Azure credentials.

```C
// Wifi
#define WIFI_SSID "{REPLACE_WITH_WIFI_SSID}" //WIFI SSID
#define WIFI_PASSWORD "{REPLACE_WITH_WIFI_PASSWORD}" //WIFI PASSWORD

// Azure IoT
#define IOT_CONFIG_IOTHUB_FQDN "{REPLACE_WITH_AZURE_IOT_URL}" //Azure IoT Hub url
#define IOT_CONFIG_DEVICE_ID "Arduino" //Device Id
#define IOT_CONFIG_DEVICE_KEY "{REPLACE_WITH_THE_DEVICE_KEY}" //Device Primary key
```

After configuring all the secrets you can compile and deploy the application to Arduino. The easiest way is to use Arduino IDE:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525838490/1eb9946b-82aa-4d28-8c60-677a2b3a09bb.jpeg align="center")

### Check that the telemetry is being received by IoT Hub

We can verify if everything is functioning properly by examining the serial output of the Arduino. If all is well, the message "Metric sent to IoT hub" should appear every 5 seconds. In addition to the serial monitor, you can also determine if everything is working by observing the Arduino RGB LED, which should blink green every 5 seconds (each time a metric is sent to Azure). If the red LED begins to blink rapidly, it indicates that something has failed. In this case, you should open the serial monitor to see what is happening.

On the Azure side, we can also monitor the telemetry being received. By executing the following commands in PowerShell, we should start seeing the telemetry data appear in Azure.

```powershell
$CONNECTION_STRING=$(az iot hub connection-string  show --hub-name ${Replace by your hub name} --output tsv) 

az iot hub monitor-events -n "${Replace by your hub name}" --login $CONNECTION_STRING --output table
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1684525910869/710120d5-c556-45af-9670-04db67ebf900.jpeg align="center")

## Next steps

At this point, we have the raw data available in Azure IoT Hub. Now we just need to parse it and start creating useful dashboards with it. This is the objective of [Part 2](https://www.hugomalves.com/build-a-room-temperature-monitor-using-azure-and-arduino-nano-part-2) of this tutorial, where we will use Azure Stream Analytics jobs and Azure Data Explorer to parse and display the data collected by the Arduino sensors.

## Common errors

| Error | Solution |
| --- | --- |
| \[ERROR\] failed, status code =-2. Trying again in 5 seconds. | Check if the azure IoT Hub root certificate is [trusted](#configure-ssl-root-trusted-certificates). |

# Extras

Code to generate a SAS token in Python. It may be useful if you want to troubleshoot its generation on Arduino. You can run this code locally and then compare the token with the one generated by Arduino.

```python
from base64 import b64encode, b64decode
from hashlib import sha256
from time import time
from urllib import parse
from hmac import HMAC

#DEVICE_KEY_IN_BASE64-copy from azure portal;
DEVICE_PRIMARY_KEY = "---"
IOT_HUB_NAME = "Arduino-demo"
DEVICE_NAME = "Arduino"

ttl = time() + 3600

sign_key = "%s\n%d" % ((parse.quote_plus(IOT_HUB_NAME + ".azure-devices.net/devices/nano")), int(ttl))
print("Signature plain text: ")
print("---")
print(sign_key)
print("---")

signature = b64encode(HMAC(b64decode(DEVICE_PRIMARY_KEY), sign_key.encode('utf-8'), sha256).digest())

rawtoken = {
    'sr' :  IOT_HUB_NAME + ".azure-devices.net/devices/" + DEVICE_NAME,
    'sig': signature,
    'se' : str(int(ttl))
}

print("SAS token:")
print('SharedAccessSignature ' + parse.urlencode(rawtoken))
```

## References

Hardware:

* [Arduino Nano RP2040 datasheet](https://content.Arduino.cc/assets/ABX00053-datasheet.pdf)
    
* [https://www.ametherm.com/thermistor/ntc-thermistors-steinhart-and-hart-equation](https://www.ametherm.com/thermistor/ntc-thermistors-steinhart-and-hart-equation)
    
* [https://www.ametherm.com/thermistor/ntc-thermistor-beta](https://www.ametherm.com/thermistor/ntc-thermistor-beta)
    
* [https://eepower.com/resistor-guide/resistor-types/ntc-thermistor/](https://eepower.com/resistor-guide/resistor-types/ntc-thermistor/)
    
* [https://files.seeedstudio.com/wiki/Grove-Temperature\_Sensor\_V1.2/res/NCP18WF104F03RC.pdf](https://files.seeedstudio.com/wiki/Grove-Temperature_Sensor_V1.2/res/NCP18WF104F03RC.pdf)
    
* [https://wiki.seeedstudio.com/Grove-Temperature\_Sensor\_V1.2/](https://wiki.seeedstudio.com/Grove-Temperature_Sensor_V1.2/)
    
* [https://ohmslawcalculator.com/voltage-divider-calculator](https://ohmslawcalculator.com/voltage-divider-calculator)
    
* [https://www.Arduino.cc/en/Tutorial/BuiltInExamples/ReadAnalogVoltage](https://www.Arduino.cc/en/Tutorial/BuiltInExamples/ReadAnalogVoltage)
    

Azure:

* [Azure SDK documentation](https://azuresdkdocs.blob.core.windows.net/$web/c/az_iot/1.0.0/index.html)
    
* [Azure SDK samples](https://github.com/Azure/azure-sdk-for-c-Arduino/tree/main/examples)
    
* [Azure IoT Hub SAS](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-dev-guide-sas)
    
* [Azure MQTT protocol](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support)
    
* [Stream analytics and power bi](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-live-data-visualization-in-power-bi)
    

Code related:

* [mbed hmac api](https://siliconlabs.github.io/Gecko_SDK_Doc/mbedtls/html/md_8h.html)
    
* [mbed base64 api](https://siliconlabs.github.io/Gecko_SDK_Doc/mbedtls/html/base64_8h.html)
    
* [mbed HMAC tutorial](https://techtutorialsx.com/2018/01/25/esp32-Arduino-applying-the-hmac-sha-256-mechanism/)
    
* [WIFINina firmware updater](https://docs.Arduino.cc/tutorials/generic/WiFiNINAFirmwareUpdater)
    

---
