In one of my previous projects, I showcased how to read data from the onboard LSM6DSO gyroscope/accelerometer. It covered the basics of how to use the Azure Sphere’s I2C bus, read from a datasheet, and write to registers at a low level. In this project, I will demonstrate how to use two click boards to create a mini weather station and send that data to the cloud.
If you have just received your Azure Sphere device, make sure to follow this getting started guide in order to get it set up first, or else all of the steps below will fail to work.
To begin, the Azure Sphere device must be connected to the Azure Cloud. In order to facilitate communication, an Azure IoT Hub service is set up in the Azure Cloud Console. First, log into the Azure Portal and click Create a resource in the top left. Then search and select IoT Hub to create it.
After filling in the necessary fields, such as the resource group and name, select the pricing tier and scale on the Size and Scale section.
Lastly, go to Review + Create and click Create to create the new IoT Hub service. Make sure to wait a couple of minutes for it to finish deploying.
Next, an IoT Hub Device Provisioning Service must be created to register the Azure Sphere device. Click on Create a resource and search for Device provisioning service. After selecting it, click Create after entering in the relevant information.
Once the resource has been deployed, click on the notification and select Pin to dashboard and then Go to resource.
In order to link the Azure Sphere device to the service, select Linked IoT Hubs and click the +Add button. Then, choose which IoT hub to use, and set the Access Policy to iothubowner. After saving, refresh the Linked IoT Hubs section to see your new link.
Now that the two IoT services are linked, it’s time to let the Azure Cloud know that your device exists and is ready to communicate. First, open up the Azure Sphere Developer Command Prompt and login with azsphere login. Then, download a Certificate Authority (CA) with azsphere tenant download-CA-certificate –output CAcertificate.cer. This creates a.cer file in the current active directory (usually Documents).
Next, navigate to the Device Provisioning Service in the Azure Portal and click on the Certificates tab on the left. Click Add and name the certificate, as well as upload the.cer that was created earlier.
The Certificate Explorer list should now show the certificate as Unverified. Click on it and view the Certificate Details. Copy the generated Verification Code to your clipboard. In the Azure Sphere Developer Command Prompt, type in the command azsphere tenant download-validation-certificate --output ValidationCertification.cer --verificationcode <code> where <code> is that verification code from the clipboard. This generates a new.cer file, which can then be uploaded to the Verification Certificate section, just underneath the Verification Code section.
Now select Manage Enrollments and click Add enrollment group. Type in a name and then choose the certificate and assign an IoT Hub. Finally, click Save.
And that’s it! Now any device in registered to the tenant will be automatically added when it first connects.
MikroE’s Environmental Click Board has a BME680 sensor at its heart.
It is able to detect temperature, humidity, pressure, and even volatile organic compounds (VOCs), such as CO2. Bosch provides a basic API, but it doesn’t play nicely with the Azure Sphere’s I2C functions, so reading from the datasheet and writing to registers directly is necessary.
Thankfully, the BME680 is an easy sensor to configure and read from. I began by creating a file that defines each necessary register’s address, such as control and data.
Reading and writing to registers via I2C on the Azure Sphere is handled differently than on an Arduino board. First, an I2C interface must be opened. This is done by adding
I2cMaster : [“ISU2”], to the
application_manifest.json file under the capabilities section.
In order to write data to a register, a pointer to an array must be passed to the
I2CMaster_Write() function. I accomplished this by creating several arrays that contain both the target address and data. For instance, in order to configure the sensor to use 1x oversampling, a value of 0x01 gets written to address 0x72.
In order to read gas data, the internal heater must first be configured. This is done through a series of calculations that determine the resistance. I created a function in main.c called
calculate_heat() that returns an 8-bit value for the resistance.
There are several constants that need to be retrieved before anything else can be done.
I first initialized several variables to store temporary values retrieved from the registers. Next, I initialized another variable called current_reg which stores the current register being written to / read from. To read data from registers, I called
I2CMaster_WriteThenRead(), which retrieves a value from a register and stores it in the variable passed to it. The datasheet outlines the calculations to perform.
Now that everything had been set up for the BME680, it was time to take some readings. The first to be read is the temperature. This is done by creating several variables for both temporary register data and more permanent data. Each time a value is read from a register, the returned value is stored and the current_reg value is set to the next register. Since the registers can only store 8-bits each, some data is split among several registers. It is then necessary to read each value into its own variable and combine them into a single value.
Bit-level manipulation is done by taking the Most Significant Bit (MSB) value and shifting it to the left by 8 bits (operation << 8) and then adding it to the LSB value. Although the temperature can be read as-is, it is best to perform some calculations to create a compensated value. Here the datasheet outlines how to do that:
The humidity, pressure, and gas are all read and calculated in a way almost identical to how the temperature is calculated. Here is a register map and some screenshots of each function.
The water detector click board is quite simple in comparison to the BME680.
It is comprised of an op-amp that sets a pin high when water is detected. On the Avnet Azure Sphere Starter Kit, this pin connects to GPIO pin 2. In order to use any GPIO pin, it must be added to the
app_manifest.json file by placing its number into the GPIO line. Next, the pin is set as an input with GPIO_OpenAsInput(2). This allows the pin’s value to be read.
To begin, a poll period of ten seconds is set, which means the device checks the cloud for new data every ten seconds. Next, it checks if there is a suitable network connection, and if so, it creates a new client with the given scope ID.
In order to see what data has been received by the cloud, a cloud function needs to be created. This takes the output from the IoT Hub service and pipes it into a console. I first went to the Azure Cloud Portal and selected Function App to bring up the Function list page. Then I clicked Add and entered the name, pricing tier, and storage. After I had created the function app, I created a new function and selected the IoT Hub template.
This allows any data from the hub to be transmitted to the function. To view the data, I edited the
index.js file to:
Events get scheduled by using a library called epoll. It allows for the easy creation of events that get triggered repeatedly at regular intervals. For this project, 4 are needed: one for the epoll itself, one to poll for new data from the cloud, one to send data to the cloud, and finally, one to check for the presence of water. It is extremely easy to assign a variable with the double datatype to what the get_sensor_data functions return.
In the function
SendData, the temperature, humidity, pressure, and gas values are all read, along with whether or not there is water present on the sensor. All of those values get sent to the cloud in JSON format.
Here is some example output:
In the near future, I am planning to create a project that displays this data in real-time via a local dashboard. A separate IoT device could then check if the conditions are getting too hot or dry and water the plants accordingly. It could also send out alerts if it senses there are too many VOCs in the air, which could indicate a possible respiratory hazard.