In past tutorials, we have seen how to install Node-RED in Raspberry Pi, and People Counting Systems with OpenCV, Python, and Ubidots. This time, we'll learn how to provision devices and use them through balena to send data to Ubidots.
Balena is a powerful set of tools for building, deploying, and managing fleets of IoT devices. balena makes it easy to manage devices and their running services, to do so you can either go through their web dashboard or the API via the CLI and SDK. Balena allows you to choose the tools you want to use for your project so the platform adapts to your needs.
In this article, we will install and run a temperature sensor in a Raspberry Pi to send data to Ubidots using balena.
Requirements
Raspberry Pi 4
SD Card
DS18B20 Temperature Sensor with 4.7k Ω Resistor
1. Setup Raspberry Pi 4 using balena
Once you have created your balena account, your first step will be to create a fleet which are the settings that will go through a group of devices. In this case, we will create a fleet that will hold Raspberry Pi 4s.
Step 1: Click on the create fleet button in the left corner
Step 2: Fill in the requested information
Step 3: After having created the first fleet you can add a device. You'll have to select:
The device
The operating system
The version
The connection to the network. It can be through Ethernet-only or through Ethernet and Wi-Fi.
Step 3: Download balena Etcher
Step 4: To flash the firmware onto an SD card you have two options, either click on flash which will automatically open balena Etcher or you can download the balenaOS to a file. For reference, we used the first option.
Step 5: Select target
Step 6: Click on Flash!
NOTE: Make sure you change any firmware settings before mounting the SD card onto the Raspberry Pi.
For instance, we had to enable the SPI port before flashing the SD card, so the OneWire protocol would work for the Temperature sensor.
2. Prepare your local computer to upload firmware changes using balena CLI
The balena CLI is a Command Line Interface for balenaCloud or openBalena. You may follow these instructions to install it in your environment.
Step 1: Install the balena CLI, you can choose from macOS, Windows, and Linux
Step 2: Add the directory in which we downloaded the CLI into your path so that you can run the same commands from any directory.
Step 3: Login into the balena from the terminal. We recommend doing the web authorization as it's a really quick and straightforward process.
3. Hardware setup
Thankfully, there's the DS18B20 digital sensor, which supports the OneWire protocol, making it quite simple to plug into your Raspberry Pi. Here's the wiring diagram for your reference:
4. Coding time
Open your preferred code editor. We'll be using Visual Studio to edit the Docker file and the Python script that reads the temperature values and sends them to Ubidots.
Step 1: Specify which OS you'd like to install into your Raspberry Pi. You can search through balenas website which OS are available.
Step 2: Docker file
Withermsernsor will be for the Temperature sensor itself.
Requests will be to send data to Ubidots.
The third command tells the Raspberry Pi which directory we will be saving all the code.
The fourth command is to copy the code.
The fifth command enables the one wired protocol in the Raspberry Pi and finally executes the "
main.py
" script.
FROM balenalib/raspberrypi4-64-debian-python:3-bullseye
RUN pip3 install w1thermsensor requests
WORKDIR /app
COPY . .
CMD modprobe w1-gpio && modprobe w1-therm && python3 main.py
Step 3: Main.py
In this code you have two parts:
The first part reads the temperature from the sensor.
The second part sends the data to Ubidots.
Copy the following code and save it as main.py
from time import sleep
import os
import requests
from w1thermsensor import W1ThermSensor #We import the W1ThermSensor package
SLEEP = os.getenv("sleep")
DEVICE = os.getenv("device")
TOKEN = os.getenv("ubi_token")
BASE_URL = "https://industrial.api.ubidots.com"
REQUESTS_FUNCTIONS = {"get": requests.get, "post": requests.post}
def main():
sensor = W1ThermSensor() #Create the sensor object
while True:
temperature = sensor.get_temperature() #Obtains the temperature in Celsius
print(f"The temperature is {temperature} celsius") #Print the result
payload = build_payload("temperature",temperature)
print(f"[INFO] Payload to send: {payload}")
req = update_device(DEVICE, payload, TOKEN)
print(f"[INFO] Request result: {req.text}")
print({"status": "Ok", "result": req.json()})
sleep(int(SLEEP))
def build_payload(variable,value):
payload = {variable:value}
return payload
def update_device(device, payload, token):
"""
updates a variable with a single dot
"""
url = "{}/api/v1.6/devices/{}".format(BASE_URL, device)
headers = {"X-Auth-Token": token, "Content-Type": "application/json"}
req = create_request(url, headers, payload, attempts=5, request_type="post")
return req
def create_request(url, headers, data, attempts, request_type):
"""
Function to create a request to the server
"""
request_func = REQUESTS_FUNCTIONS.get(request_type)
kwargs = {"url": url, "headers": headers}
if request_type == "post":
kwargs["json"] = data
try:
req = request_func(**kwargs)
print("[INFO] Request result: {}".format(req.text))
status_code = req.status_code
sleep(1)
while status_code >= 400 and attempts < 5:
req = request_func(**kwargs)
print("[INFO] Request result: {}".format(req.text))
status_code = req.status_code
attempts += 1
sleep(1)
return req
except Exception as e:
print("[ERROR] There was an error with the request, details:")
print(e)
return None
if __name__ == "__main__":
main()
In this case, we will be using the OS library to get the environment variables and import them into the code, these environment variables can be set up through balena.
In this example, we created the following variables:
Sleep is the time interval between measurements.
Device is the label of the device that will be created in Ubidots
Token to authenticate HTTP requests sent from the device to the cloud.
Step 4: You need to add one line of code to the settings file to accept the one wired protocol. Go to the balena tutorial and copy the line and add it into the config TXT file of the flash of your SD card.
Step 5: Upload the code into balena: go to the directory where the code is saved and run the command balena push
and the name of your fleet. For example, since the name of our fleet was "testingfleet", the command would be:
balena push testingfleet
You know that the code has been uploaded successfully once you see a unicorn.
5. Managing environmental variables in balena
One of the cool things about balena is the ability to set configuration parameters directly in the cloud, which makes it easy to manage a large fleet of devices remotely.
Step 1: Go to balena and click on your device name
Step 2: Select Device Variables
Step 3: Click on Add variable
Step 4: As mentioned above, we created 3 variables: token, device, and sleep.
To get the Ubidots Token you need to go to your Ubidots account. Click on API credentials, copy the token, and past it in balena.
Once these variables have been set, balena will upload the newest version of the container into the Raspberry Pi including the changes of the variables that we just did.
6. Results
Step 1: Go to the devices menu at Ubidots. There you can find the new device,
now you can see the data that is being sent from balena to Ubidots.
Others also found useful: