---
title: Sensor Tutorial with Python and Raspberry Pi
description: Build an MCU-controlled application that reads from an external sensor and sends readings to the Notecard to start building your IoT application using Cellular, Satellite, LoRa, or WiFi connectivity.
source_url: https://dev.blues.io/guides-and-tutorials/collecting-sensor-data/raspberry-pi/python/
canonical_url: https://dev.blues.io/guides-and-tutorials/collecting-sensor-data/raspberry-pi/python/
markdown_url: https://dev.blues.io/guides-and-tutorials/collecting-sensor-data/raspberry-pi/python.md
---

# Collecting Sensor Data Python and Raspberry Pi

*Don't see your favorite hardware here? Rest assured the Notecard works with virtually every MCU and SBC available. If you can't figure out how to complete this tutorial [let us know in our forum](https://discuss.blues.com/) and we can help you out.*

## Introduction

*This tutorial should take approximately 40-50 minutes to complete.*

In this tutorial, you'll learn how to take sensor data, queue it on your Notecard, and synchronize it to Blues Notehub. You'll use **Python** running on a **Raspberry Pi**. If you would like to use a different language or board, modify the dropdowns at the top of this guide. And if you get stuck at any point, feel free to reach out for help in our [community forum](https://discuss.blues.com).

This tutorial uses mock sensor readings for simplicity, but feel free to hook up a physical sensor of your choice and use that instead. The goal of this tutorial is to demonstrate reusable firmware techniques you can apply to your own Notecard-based projects.

## Set up Hardware

> **Note:**
>
> This tutorial assumes you have already wired your Notecard to your host. If you haven't, complete the [Host Wiring Guide](https://dev.blues.io/guides-and-tutorials/host-wiring-guide.md) before continuing.

In order to complete this guide, you'll need the following:

- A Notecard mounted to a Notecarrier Pi. *Be sure to use standoffs to secure the Notecarrier Pi to your Raspberry Pi to prevent a short between the external SIM slot on the Notecarrier Pi and the HDMI out port on the Raspberry Pi.*

- A Raspberry Pi. *Any Single-Board Computer with a Raspberry Pi-compatible 40-pin connector, along with Pip and Python 3.x.x will do. If you plan to use a Raspberry Pi-compatible device, see the [Notecarrier Pi Datasheet](https://dev.blues.io/datasheets/notecarrier-datasheet/notecarrier-pi-v2-0.md#notecarrier-pi-40-pin-header) for pin configuration info.*

- A text editor for writing a Python script on the Raspberry Pi. *For the sake of this tutorial, `nano` is sufficient and is installed by default on Raspberry Pi OS. For a better experience, you can use VSCode with the "Remote - SSH" and "Python" extensions installed.*

> **Warning:**
>
> Due to the power requirements of the Notecard, some Raspberry Pi 2 and 3 models include a current-limiting fuse that will power-cycle the device when the Notecard's modem is on and transmitting. To avoid these issues, *we recommend using only Raspberry Pi 4 or 5 devices with the Notecard and a Notecarrier*.

### Connect the Raspberry Pi to the Notecarrier Pi

1. Plug the Notecarrier Pi into the 40-pin GPIO header of your Raspberry Pi.

And you're done!

## Create a Notehub Project

Now that your hardware is all connected, let's create a new Notehub project to receive sensor readings from your Notecard.

1. Navigate to [notehub.io](https://notehub.io) and log in, or create a new account.

2. Click the **Create Project** button.

3. In the New Project dialog, give your project a name and ProductUID.

   ![How to create a new Notehub project](https://dev.blues.io/images/guides/notehub/create-project.png?v=bf29a47a)

   > **Note:**
   >
   > The ProductUID must be globally unique, so we recommend a namespaced name like `"com.your-company.your-name:your_product"`.

4. Take note of your ProductUID. This identifier is used by Notehub to associate your Notecard with your project.

   ![Where to find your product UID](https://dev.blues.io/images/guides/notehub/product-uid.png?v=d829ab1d)

## Write Firmware

> **Tip:**
>
> This tutorial shows how to write host firmware by hand so you can understand the fundamentals. In practice, we recommend using an AI coding assistant with Blues Expert MCP for development. Blues Expert MCP connects your AI coding assistant (Claude Code, GitHub Copilot, Cursor) directly to our API docs, providing live request validation and firmware best practices for Arduino, C, Zephyr, and Python. [Install the Blues Expert MCP →](https://dev.blues.io/tools-and-sdks/generative-ai-tools/blues-expert-mcp.md)

Now you're ready to build your app. Before writing code, you'll need to `ssh` into your Raspberry Pi from a terminal program and configure I2C communications.

### Configure the Raspberry Pi

#### Configure I2C for the Notecard and Raspberry Pi

The Notecarrier Pi uses I2C for communication from the Raspberry Pi. To enable I2C, use the `raspi-config` utility.

1. From a Pi terminal session, launch the "Raspberry Pi Software Configuration Tool (raspi-config)."

```bash
sudo raspi-config
```

2. Select **Interface Options**.

   ![raspi-config Interface Options](https://dev.blues.io/images/guides/first-sensor/rpi/interfacing-options.png?v=0c6b5286)

3. Select **P5 I2C**.

   ![raspi-config P5 I2C option](https://dev.blues.io/images/guides/first-sensor/rpi/select-i2c.png?v=52cf80c9)

4. For *"Would you like the ARM I2C interface to be enabled?"*, select **\<Yes>**.

   ![Enable ARM I2C prompt](https://dev.blues.io/images/guides/first-sensor/rpi/arm-i2c.png?v=3b022b96)

5. The next screen will confirm your selection, and should read, *"The ARM I2C interface is enabled"*. Select **\<OK>**.

   ![ARM I2C enabled confirmation](https://dev.blues.io/images/guides/first-sensor/rpi/i2c-enabled.png?v=5605bf7e)

6. Right arrow twice, and select **\<Finish>**.

   ![raspi-config Finish selection](https://dev.blues.io/images/guides/first-sensor/rpi/finish.png?v=495f3bee)

7. If prompted, *"Would you like to reboot now?"*. Select **\<Yes>**.

#### Install I2C Helper Tools

1. Once your Pi comes back online, SSH back into the device.

2. Install the `i2c-tools` package, so you can confirm connections to I2C devices.

```bash
sudo apt-get install -y i2c-tools
```

3. Run `i2cdetect` to ensure the Notecard is detected.

```bash
sudo i2cdetect -y 1
```

![i2cdetect Notecard address output](https://dev.blues.io/images/guides/first-sensor/rpi/pi-i2c-detect.png?v=55a12b25)

> You should see `17` in the output. This means a device responded at `0x17`, which is the I2C address of the Notecard.

### Write Code

> **Warning:**
>
> By default, the Notecarrier Pi provides *only* an I2C connection between the Pi host and the Notecard. To enable Serial communication, the [SERIAL TXRX](https://dev.blues.io/datasheets/notecarrier-datasheet/notecarrier-pi-v2-0.md#dip-switches) dip switch must be toggled to the `ON` position.

To communicate with the Notecard over I2C, you'll need to install the `note-python` and `python-periphery` libraries. And to generate mocked sensor readings, you'll need to install the `notecard-pseudo-sensor` library.

1. To use the [`note-python`](https://github.com/blues/note-python), [`notecard-pseudo-sensor`](https://github.com/blues/notecard-pseudo-sensor-python/), and [`python-periphery`](https://github.com/vsergeev/python-periphery) libraries you'll need to install them using `pip3`.

```bash
pip3 install note-python notecard-pseudo-sensor python-periphery
```

2. In your project directory, create a new file called `sensors.py`.

```bash
nano sensors.py
```

3. Add the following imports to the top of the file:

```python
import json
import notecard
import notecard_pseudo_sensor
from periphery import I2C
import time
```

4. Next, add a variable for your ProductUID using the value you specified when creating your Notehub project:

```python
productUID = "com.your-company.your-name:your_product"
```

5. Configure the I2C connection to your Notecard, and initialize it using the `OpenI2C` function:

```python
port = I2C("/dev/i2c-1")
card = notecard.OpenI2C(port, 0, 0)
```

6. Now, we'll configure the Notecard. We will use the `hub.set` request to associate this Notecard with the ProductUID of your project, as well as set the Notecard to operate in `continuous` mode (indicating the device should immediately make a connection to Notehub and keep it active).

```python
req = {"req": "hub.set"}
req["product"] = productUID
req["mode"] = "continuous"
 
print(json.dumps(req))
 
rsp = card.Transaction(req)
print(rsp)
```

> The lines above build-up a JSON object by adding two string values for product and mode, and then fire the request off to the Notecard with the `Transaction` function.

7. Save and exit the `sensors.py` file. From the same directory, use the `python3` interpreter to run the program.

```python
python3 sensors.py
```

```python
{"req": "hub.set", "product": "com.your-company.your-name:your_product", "mode": "continuous"}
{}
```

If your terminal output looks similar to that above, then you are talking to your Notecard and all of your hardware is configured correctly!

### Read from the Sensor

Now that you've configured your Raspberry Pi to communicate with the Notecard, let's grab some pseudo sensor readings.

> **Note:**
>
> If you have your own sensor, feel free to hook it up and use your own values instead of this tutorial's mocked ones.

1. Add the line below to instantiate a new instance of the sensor class for generating mock values.

```python
sensor = notecard_pseudo_sensor.NotecardPseudoSensor(card)
```

2. Add a `while True` block to the bottom of your `sensors.py` file that uses the code below. Now the program will take a mocked temperature and humidity reading, and print those values to the console before sleeping for 15 seconds and repeating.

```python
while True:
  temp = sensor.temp()
  humidity = sensor.humidity()
  print('Temperature: {} degrees C'.format(temp))
  print('Humidity: {}%'.format(humidity))
 
  time.sleep(15)
```

3. Save and exit the `sensors.py` file. From the same directory, use the `python3` interpreter to run the program. Only this time, after the Notecard request and response statements, you'll see the temperature and humidity values logged to the terminal every 15 seconds.

```unknown
python3 sensors.py
```

```unknown
{"req": "hub.set", "product": "com.your-company.your-name:your_product", "mode": "continuous"}
{}
Temperature: 33.875 degrees C
Humidity: 49.9511%
...
```

### Send Sensor Readings to the Notecard

Now that we're getting sensor readings, let's send these to our Notecard.

1. To send a sensor reading to the Notecard, we'll need to construct a new JSON request to the `note.add` API that includes a new Notefile name (`sensors.qo`), sets the `sync` field to `True` (to instruct the Notecard to sync to Notehub immediately), and finally, sets the `body` to the sampled temperature and humidity. Add the following to the `while True:` loop, after the `print()` statements used to print out the readings.

```python
req = {"req": "note.add"}
req["file"] = "sensors.qo"
req["sync"] = True
req["body"] = { "temp": temp, "humidity": humidity }
```

2. To send the request to your Notecard and read the result, add the following just before the `time.sleep(15)` statement:

```python
rsp = card.Transaction(req)
print(rsp)
```

3. Save and exit the `sensors.py` file. From the same directory, use the `python3` interpreter to run the program. As it executes, the program output will update to display the response from the `note.add` request (the total number of Notes in the notefile) each time you add a new reading.

```python
python3 sensors.py
```

```python
{"req": "hub.set", "product": "com.your-company.your-name:your_product", "mode": "continuous"}
{}
Temperature: 24.431171875 degrees C
Humidity: 50.35774813702876%
{"total": 1}
Temperature: 24.4348828125 degrees C
Humidity: 50.418771430827704%
{"total": 2}
...
```

## View Data in Notehub

Once you start capturing readings, your Notecard will initiate a connection to Notehub and will start transferring Notes. Depending on signal strength and coverage in your area, it may take a few minutes for your Notecard to connect to Notehub and transfer data.

1. Return to [notehub.io](https://notehub.io) and open your project. You should see your Notecard in the Devices view.

   ![The new device in Notehub](https://dev.blues.io/images/guides/notehub/new-device.png?v=f506b425)

   > **Note:**
   >
   > Each Notecard has a factory-assigned, globally unique identifier known as a [DeviceUID](https://dev.blues.io/api-reference/glossary.md#deviceuid). Notehub uses this identifier in the Devices view by default (for example, `dev:868531061604976` in the screenshot above).
   >
   > If you’d prefer to use your own identifier—such as a human-readable name or an internal ID—you can assign a [serial number](https://dev.blues.io/api-reference/glossary.md#product-sn) to your Notecard in one of the following ways:
   >
   > - **In Notehub:** Double-click your device in the Devices view to open its details, where you can edit the serial number.
   > - **Via the Notehub API:** Set the reserved `_sn` environment variable using the [Set Device Environment Variables](https://dev.blues.io/api-reference/notehub-api/device-api.md#set-device-environment-variables) endpoint.
   > - **Via the Notecard API**: Include an `sn` argument in the [hub.set request](https://dev.blues.io/api-reference/notecard-api/hub-requests/latest.md#hub-set) you used to configure your Notecard.

2. Now, click on the Events left menu item. Once your sensor Notes start syncing, they'll show up here. You may need to refresh the page to see newly synced Notes.

   ![The event list in Notehub](https://dev.blues.io/images/guides/notehub/events.png?v=76323245)

## Use Environment Variables

[Environment variables](https://dev.blues.io/guides-and-tutorials/notecard-guides/understanding-environment-variables.md) are a Notehub state and settings management feature that allow you to set variables in key-value pairs, and intelligently synchronize those values across devices and fleets of devices.

In this section you'll learn how environment variables work by creating a variable that determines how often your firmware should take sensor readings.

### Using Environment Variables in Firmware

The Notecard provides [a set of requests for working with environment variables](https://dev.blues.io/api-reference/notecard-api/env-requests.md). The most common of these requests is [`env.get`](https://dev.blues.io/api-reference/notecard-api/env-requests.md#env-get), which allows you to retrieve the value of an environment variable.

Complete the steps below to use the `env.get` request to retrieve and use the `reading_interval` environment variable.

1. First, adjust your existing `hub.set` configuration to set the `inbound` argument to `5`. This tells your Notecard to look for inbound changes from Notehub every 5 minutes.

   ```python
   req = {"req": "hub.set"}
   req["product"] = productUID
   req["mode"] = "continuous"
   req["inbound"] = 5 # add this line
   rsp = card.Transaction(req)
   ```

2. Next, place the following new function before the existing `while True` loop.

   ```python
   # This function assumes you’ll set the reading_interval environment variable to
   # a positive integer. If the variable is not set, set to 0, or set to an invalid
   # type, this function returns a default value of 60.
   def get_sensor_interval():
      sensor_interval_seconds = 60
      req = {"req": "env.get"}
      req["name"] = "reading_interval"
      rsp = card.Transaction(req)
      try:
         reading_interval = int(rsp.get("text", ""))
         if reading_interval > 0:
            sensor_interval_seconds = reading_interval
      except (AttributeError, TypeError, ValueError):
         pass
      return sensor_interval_seconds
   ```

3. Finally, find the existing `time.sleep(15)` line in your `while True` loop, and replace it with the code below.

   ```python
   sensor_interval_seconds = get_sensor_interval()
   print(f"Delaying {sensor_interval_seconds} seconds")
   time.sleep(sensor_interval_seconds)
   ```

   > **Note:**
   >
   > Notecard for LoRa requires a template for each environment variable you use. If you're using a Notecard for LoRa to complete this tutorial, add the code below alongside your other Notecard configuration (before your `while True` loop) to provide a template for the `reading_interval` variable.
   >
   > ```python
   > req = {"req": "env.template"}
   > req["body"] = {"reading_interval": 21}
   > card.Transaction(req)
   > ```
   >
   > Here `21` is the type hint for a 1-byte unsigned integer (`0`–`255`). If your `reading_interval` may exceed 255, use `22` (a 2-byte unsigned integer) instead.

Your firmware now uses the `reading_interval` environment variable to determine how many seconds to delay in between sensor readings.

Save and exit the `sensors.py` file. From the same directory, use the `python3` interpreter to run the program. You should see your device using the default `reading_interval` value of 60 seconds.

### Setting an Environment Variable

Now that we have our device programmed to retrieve an environment variable from Notehub, we will create that variable. Environment variables can be set in the Notehub UI or through the Notehub API. In this tutorial you'll learn how to set the values through the Notehub UI. If you'd like to instead set environment variables through the Notehub API, refer to environment variable requests in the [Project API](https://dev.blues.io/api-reference/notehub-api/project-api.md).

1. Return to your Notehub project, go to the **Devices** page, and double click your device. You should see a screen that looks like this.

   ![The Notehub device screen](https://dev.blues.io/images/guides/first-sensor/environment/device-screen.png?v=cdb91b6c)

2. Click the **Environment** tab.

3. Under the **Device environment variables** header, define a new environment variable named `reading_interval` and set its value to `30`.

   ![The environment screen with a new value set](https://dev.blues.io/images/guides/first-sensor/environment/setting-a-variable.png?v=e576ef35)

Now that you have an environment variable set, you'll see it reflected on your device **after your configured `inbound` interval has passed**.

```python
python3 sensors.py
```

```python
...
Temperature: 19.9 C
Humidity: 49.3 %
{"req": "note.add", "body": {"humidity": 49.3467, "temp": 19.875}, "sync": true, "file": "sensors.qo"}
{"total":1}
{"name": "reading_interval", "req": "env.get"}
{"text":"30"}
Delaying 30 seconds
```

> **Note:**
>
> On cellular and WiFi-based Notecards you can use the [`hub.set` request](https://dev.blues.io/api-reference/notecard-api/hub-requests/latest.md#hub-set)'s `sync` argument to immediately receive inbound updates instead of relying on the `inbound` interval.

And with that, you've used your first environment variable on your Notecard! To see the real power of environment variables in action, try returning to Notehub and updating your device's `reading_interval` with your serial monitor open.

> **Note:**
>
> This tutorial covers several configuration settings that are best used when you have your Notecard connected to mains power.
>
> - In the `hub.set` request, setting `mode` to `"continuous"` tells the Notecard to maintain an active network connection.
>
> - In the `hub.set` request, the `sync` argument (when set to `true`) tells the Notecard to immediately synchronize inbound Notes and environment variables from Notehub.
>
> - In the `note.add` request, setting `sync` to `true` tells the Notecard to immediately synchronize all outbound Notes to Notehub.
>
> Because each of these settings causes the Notecard to use more power, you may wish to disable them if you plan to transition your project to battery power. You can run the command below to put your Notecard into `periodic` mode with the `sync` argument turned off.
>
> ```json
> {
>  "req": "hub.set",
>  "mode": "periodic",
>  "sync": false,
>  "outbound": 60,
>  "inbound": 120
> }
> ```
>
> For a deeper look at how these settings work together, watch [An In-Depth Guide to Notecard’s hub.set Request](https://www.youtube.com/watch?v=3D2p1t8UMHQ). The video steps through complete configuration scenarios that show how your choice of `mode`, `outbound`, `inbound`, and `sync` values determines exactly when your Notecard connects and syncs with Notehub.

## Next Steps

**Congratulations!** You've successfully connected your Raspberry Pi to your Notecard and built a basic IoT project.

If you're following a Cell+WiFi Quickstart, next we recommend learning how to send (and visualize) your data in a cloud application:

1. ~~Use the Notecard to Send Data~~
2. ~~Host Wiring Guide~~
3. ~~Build Your First IoT App With Blues~~
4. [Send Data to Your Cloud](https://dev.blues.io/guides-and-tutorials/routing-data-to-cloud.md)

At any time, if you find yourself stuck, please reach out on the [community forum](https://discuss.blues.com/).
