
Hi !
In my previous post I shared a Python script that reads value from a Grove sensor and send the values as device telemetry to Azure IoT Hub. In today’s post I’ll share some insights and lessons learned on how to pack this as an Azure IoT Module.
In the references section I shared a Microsoft Docs tutorial on how to create a Azure IoT Module. That article cover the core steps to create the module using Visual Studio Code. I’ll focus on the main changes that we need to perform to make the module work.
Module Code
The module code is similar to the previous posts. The main difference will be around how the code and threads are managed. Based on the Azure IoT Python template, I’m using asyncio to work with threads. Another change is that, in this scenario, the interval timer will be defined as an environmental variable in the module definition.
Docker Permission to grant low level hardware access
Our module will interact with GPIO, so when we define and create the module for our device, in the Container Create Options, we need to add the following lines:
{
"HostConfig": {
"Binds":[
"/dev/i2c-1:/dev/i2c-1"
],
"Privileged": true
}
}
Enabling access to the i2c and also running the module with elevated privileges:

Install Grove dependencies on the Docker Image
This one took me some try & test & fail & learn until I figure it out. So, we need to add this dependencies in the requirements.txt file:
azure-iot-device~=2.0.0
RPi.GPIO
grove.py
seeed-python-dht
However, when I build the image remotely in my device I got the following error
Running setup.py install for RPi.GPIO: started
Running setup.py install for RPi.GPIO: finished with status 'error'
ERROR: Command errored out with exit status 1:
command: /usr/local/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-zxn0f5l4/rpi-gpio_20705074d6cc4e37b7794843814bcb85/setup.py'"'"'; __file__='"'"'/tmp/pip-install-zxn0f5l4/rpi-gpio_20705074d6cc4e37b7794843814bcb85/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-4mka4lwh/install-record.txt --single-version-externally-managed --compile --install-headers /usr/local/include/python3.7m/RPi.GPIO
cwd: /tmp/pip-install-zxn0f5l4/rpi-gpio_20705074d6cc4e37b7794843814bcb85/
Complete output (16 lines):
running install
running build
running build_py
creating build
creating build/lib.linux-armv7l-3.7
creating build/lib.linux-armv7l-3.7/RPi
copying RPi/__init__.py -> build/lib.linux-armv7l-3.7/RPi
creating build/lib.linux-armv7l-3.7/RPi/GPIO
copying RPi/GPIO/__init__.py -> build/lib.linux-armv7l-3.7/RPi/GPIO
running build_ext
building 'RPi._GPIO' extension
creating build/temp.linux-armv7l-3.7
creating build/temp.linux-armv7l-3.7/source
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/usr/local/include/python3.7m -c source/py_gpio.c -o build/temp.linux-armv7l-3.7/source/py_gpio.o
unable to execute 'gcc': No such file or directory
error: command 'gcc' failed with exit status 1
----------------------------------------
ERROR: Command errored out with exit status 1: /usr/local/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-zxn0f5l4/rpi-gpio_20705074d6cc4e37b7794843814bcb85/setup.py'"'"'; __file__='"'"'/tmp/pip-install-zxn0f5l4/rpi-gpio_20705074d6cc4e37b7794843814bcb85/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-4mka4lwh/install-record.txt --single-version-externally-managed --compile --install-headers /usr/local/include/python3.7m/RPi.GPIO Check the logs for full command output.
The command '/bin/sh -c pip install -r requirements.txt' returned a non-zero code: 1
As I mentioned, this took me some time until I figure out the right dependencies, and at the end I added 2 changes to my docker to make it work. I updated the [Dockerfile.arm32v7] and end it with these content
FROM arm32v7/python:3.7-slim-buster
WORKDIR /app
# custom installation for RPI Grove dependencies defined in requirements.txt
RUN apt-get update
RUN apt-get install -y gcc
COPY requirements.txt ./
RUN pip install -r requirements.txt
COPY . .
CMD [ "python3", "-u", "./main.py" ]

Full module source is available here https://github.com/elbruno/Blog/tree/main/20210308%20AzureIoT%20Module%20Rpi%20Grove%20Temp/ebGroveTemperatureDht11
In tomorrow post, I’ll share the final steps to have the module up and running with Azure IoT.
References
- Seeedstudio, Grove
- Create an IoT hub using the Azure portal
- Tutorial: Develop and deploy a Python IoT Edge module for Linux devices
Happy coding!
Greetings
El Bruno
More posts in my blog ElBruno.com.
More info in https://beacons.ai/elbruno
Azure ☁ IoT
- Install ☁ Azure IoT on Raspberry Pi
- Deploy ☁ Azure Blob Storage on IoT Edge, lessons learned
- Connect to ☁ Azure Blob Storage on IoT Edge using Microsoft Azure Storage Explorer
- Lesson learned and tips on how to install Azure IoT Edge on Ubuntu on a Raspberry Pi
- Azure IoT Explorer, in preview and awesome
- Mapping a local ☁ Azure IoT Edge folder module with an Edge device folder 📁
- Creating a folder 📂 in the docker definition in an ☁ Azure IoT Edge
- Granting access to Raspberry Pi GPIO from an ☁ Azure IoT Edge Module
Create an Azure IoT Module using Raspberry Pi and Grove Sensors
- Raspberry Pi + Grove Sensors, read temperature and humidity values
- Raspberry Pi + Grove Sensors, send temperature and humidity values as telemetry to Azure IoT Hub
- Raspberry Pi + Grove Sensors, create a Azure IoT Module to send temperature and humidity values as telemetry to Azure IoT Hub
- Raspberry Pi + Grove Sensors, publish and use the Azure IoT Module
- Raspberry Pi + Grove Sensors, notes on build and configuration
- Raspberry Pi + Grove Sensors, details on how to send a telemetry message and sample messages
Create an Azure IoT Module from Azure Custom Vision project
- Create and export a Custom Vision Project as Docker image
- Analyze the content of the CV Docker image
- Create and analyze an Azure IoT Module
- Merge the CV project as an Azure IoT Module
- Deploy to an Azure IoT device and test the CV module
- Send telemetry for each analyzed image
- Add digital twin configuration to the Azure IoT module (coming soon)
¿Con ganas de ponerte al día?
En Lemoncode te ofrecemos formación online impartida por profesionales que se baten el cobre en consultoría:
- Si tienes ganas de ponerte al día con Front End (ES6, Typescript, React, Angular, Vuejs…) te recomendamos nuestros Máster Front End: https://lemoncode.net/master-frontend#inicio-banner
- Si te quieres poner al día en Backend (stacks .net y nodejs), te aconsejamos nuestro Bootcamp Backend: https://lemoncode.net/bootcamp-backend#bootcamp-backend/banner
- Y si tienes ganas de meterte con Docker, Kubernetes, CI/CD…, tenemos nuestro Bootcamp Devops: https://lemoncode.net/bootcamp-devops#bootcamp-devops/inicio