AI & Agents

How to Read Analog Sensors on a Raspberry Pi with an ADC and OpenClaw

Raspberry Pi GPIO pins are digital-only, so reading a thermistor, soil moisture probe, or light sensor requires an external ADC chip. This guide compares the four most common options (MCP3008, MCP3208, ADS1015, ADS1115), walks through wiring and Python code for both SPI and I2C setups, and shows how to connect the data pipeline to an OpenClaw agent that logs readings and pushes them to a persistent cloud workspace.

Fast.io Editorial Team 12 min read
An AI agent processing sensor data and sharing results through a cloud workspace

Why Every Pi Sensor Project Starts with an ADC

Raspberry Pi has shipped over 75 million units since 2012, yet not a single model includes a built-in analog-to-digital converter. Every one of the Pi's 40-pin GPIO header pins reads digital signals: high (3.3V) or low (0V). That is fine for buttons, LEDs, and digital sensors, but the majority of real-world sensing requires measuring a continuous voltage that varies between zero and some reference level. Temperature, light intensity, soil moisture, air pressure, gas concentration, battery level: these all produce analog output that the Pi cannot read natively.

An ADC (Analog-to-Digital Converter) bridges the gap. It is a chip that samples an analog voltage at regular intervals and converts each sample into a discrete numeric value. A 10-bit ADC produces values from 0 to 1023. A 16-bit ADC produces values from 0 to 65,535, giving roughly 64 times finer resolution for the same voltage range. The Pi communicates with the ADC over SPI or I2C, reads the digital value, and converts it to a voltage or engineering unit in software.

Most Raspberry Pi ADC tutorials walk through wiring a single chip and printing readings to a terminal. That is useful for a bench test but useless for anything that needs to run unattended: a greenhouse monitor that alerts when soil dries out, a server room sensor that logs temperature every minute, or a weather station that archives readings for weeks. The missing piece is an automation layer that watches sensor data, reacts to thresholds, and persists logs somewhere accessible.

OpenClaw is an open-source AI agent framework that runs directly on a Raspberry Pi. It can execute shell commands, schedule recurring tasks, monitor files for changes, and send data to cloud storage. Pairing an ADC hardware setup with an OpenClaw agent turns a one-off sensor reading into a continuous, self-managing data pipeline. This guide covers chip selection, wiring, Python code, and the agent integration that most tutorials skip.

How to Choose the Right ADC Chip for Your Project

Four ADC breakout boards cover the majority of Raspberry Pi sensor projects. The right choice depends on how many sensors you need, how precise your readings must be, and whether you prefer SPI or I2C wiring.

Chip Resolution Channels Interface Max Sample Rate Programmable Gain Price (Adafruit)
MCP3008 10-bit (0-1023) 8 SPI 200 ksps No $4.50
MCP3208 12-bit (0-4095) 8 SPI 100 ksps No $3-5 (bare chip)
ADS1015 12-bit (signed) 4 I2C 3,300 sps Yes (2/3x to 16x) $9.95
ADS1115 16-bit (signed) 4 I2C 860 sps Yes (2/3x to 16x) $14.95

MCP3008 is the default starter chip. Eight channels cover most hobby projects, 10-bit resolution is adequate for reading potentiometers, photoresistors, and basic temperature sensors, and the $4.50 price point makes mistakes cheap. It communicates over SPI, which requires four wires (MOSI, MISO, SCLK, CS) plus one additional CS pin per extra MCP3008 if you need more than eight channels.

MCP3208 is the MCP3008's higher-resolution sibling. Same eight channels and SPI interface, but 12-bit resolution gives four times the precision per channel. Microchip sells the bare IC for a few dollars, though no major breakout board vendor offers a pre-built module. Pick this when you need more than 10 bits but want to stay on SPI.

ADS1015 splits the difference on price and precision. It offers 12-bit resolution over I2C with a programmable gain amplifier (PGA) that can measure voltages as small as 0.256V full-scale, useful for strain gauges and low-output sensors. Its 3,300 samples-per-second rate is the fast of the four for applications that need rapid polling. Four I2C address options let you daisy-chain up to four chips (16 channels) on two wires.

ADS1115 is the precision pick. At 16-bit resolution, it resolves voltage changes as small as 0.1875 millivolts on the default gain setting. The same PGA and I2C address options as the ADS1015 apply. The tradeoff is speed: maximum 860 samples per second, which is more than enough for environmental monitoring but too slow for audio or vibration analysis. At $14.95 it costs three times the MCP3008, but the added precision and simpler two-wire I2C connection make it the better choice for serious measurement projects.

Which one should you pick? For a first project or anything with five or more analog inputs on a budget, start with the MCP3008. For precision measurement, scientific logging, or projects where you want minimal wiring, choose the ADS1115. The ADS1015 fits the gap when you need faster sampling at moderate resolution. The MCP3208 is worth sourcing if you already know SPI and want 12-bit without paying the ADS1115 premium.

Structured data comparison and analysis pipeline

Wiring and Reading the MCP3008 over SPI

The MCP3008 connects to the Raspberry Pi's hardware SPI bus. You need six jumper wires.

Pin connections (MCP3008 to Raspberry Pi):

  • VDD (pin 16) to 3.3V (physical pin 1)
  • VREF (pin 15) to 3.3V (physical pin 1)
  • AGND (pin 14) to GND (physical pin 6)
  • DGND (pin 9) to GND (physical pin 6)
  • CLK (pin 13) to SCLK (physical pin 23, GPIO 11)
  • DOUT (pin 12) to MISO (physical pin 21, GPIO 9)
  • DIN (pin 11) to MOSI (physical pin 19, GPIO 10)
  • CS (pin 10) to CE0 (physical pin 24, GPIO 8)

Connect your analog sensor's output to one of the eight input channels (CH0 through CH7, pins 1 through 8). A potentiometer is the easiest test: wire the outer legs to 3.3V and GND, and the wiper to CH0.

Enable SPI on the Pi:

sudo raspi-config

Navigate to Interfacing Options, select SPI, and enable it. Reboot afterward.

Install the Adafruit CircuitPython library:

pip install adafruit-circuitpython-mcp3xxx

On Raspberry Pi OS Bookworm and later, you may need to create a virtual environment first or use the --break-system-packages flag.

Read channel 0:

import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn

spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
cs = digitalio.DigitalInOut(board.D8)
mcp = MCP.MCP3008(spi, cs)
channel = AnalogIn(mcp, MCP.P0)

print(f"Raw: {channel.value}  Voltage: {channel.voltage:.3f}V")

The value property returns a 16-bit scaled integer (0 to 65535) for consistency across Adafruit's ADC libraries. The voltage property converts that to actual volts based on the reference voltage. To get the native 10-bit reading, divide value by 64.

For raw SPI access without the Adafruit library, the spidev package gives direct control:

import spidev

spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1350000

def read_channel(ch):
    r = spi.xfer2([1, (8 + ch) << 4, 0])
    return ((r[1] & 3) << 8) + r[2]

print(f"Channel 0: {read_channel(0)}")

This returns the raw 10-bit value (0 to 1023) directly.

Wiring and Reading the ADS1115 over I2C

The ADS1115 uses the I2C bus, which means only four wires total.

Pin connections (ADS1115 breakout to Raspberry Pi):

  • VDD to 3.3V (physical pin 1)
  • GND to GND (physical pin 6)
  • SCL to SCL (physical pin 5, GPIO 3)
  • SDA to SDA (physical pin 3, GPIO 2)

Connect your sensor output to one of the four analog inputs (A0 through A3). The ADDR pin sets the I2C address: connect to GND for 0x48 (default), VDD for 0x49, SDA for 0x4A, or SCL for 0x4B.

Enable I2C on the Pi:

sudo raspi-config

Navigate to Interfacing Options, select I2C, and enable it. After rebooting, verify the chip is detected:

i2cdetect -y 1

You should see 48 in the address grid.

Install the Adafruit CircuitPython library:

pip install adafruit-circuitpython-ads1x15

Read channel A0:

import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1115(i2c)
channel = AnalogIn(ads, ADS.P0)

print(f"Raw: {channel.value}  Voltage: {channel.voltage:.4f}V")

Using the programmable gain amplifier:

The ADS1115's PGA lets you adjust the full-scale voltage range without external circuitry. The default gain of 2/3 gives a range of +/-6.144V (though the input voltage should never exceed VDD + 0.3V). For a 3.3V sensor, gain of 1 (+/-4.096V) uses more of the ADC's 16-bit range. For millivolt-level signals, gain of 16 (+/-0.256V) gives the finest resolution:

ads.gain = 16
channel = AnalogIn(ads, ADS.P0)
print(f"Voltage: {channel.voltage:.6f}V")

Available gain values: 2/3, 1, 2, 4, 8, 16.

Differential measurement:

For noise-sensitive applications, the ADS1115 can measure the voltage difference between two inputs rather than each input relative to ground:

from adafruit_ads1x15.analog_in import AnalogIn

diff_channel = AnalogIn(ads, ADS.P0, ADS.P1)
print(f"Differential: {diff_channel.voltage:.4f}V")

This is particularly useful for bridge sensors (load cells, strain gauges) where the signal rides on a common-mode voltage.

Fastio features

Store and query your sensor data from any device

A shared workspace with a built-in MCP endpoint. Upload CSVs, query readings through Intelligence Mode, and share results with your team. Starts with a 14-day free trial.

How to Build an OpenClaw Agent Pipeline for Sensor Data

Reading an ADC value once proves the hardware works. Making it useful requires a loop that samples continuously, stores results, and reacts when readings cross a threshold. OpenClaw handles the automation layer so you do not need to write a custom daemon or systemd service.

The data capture script

Create a Python script that reads your ADC in a timed loop and writes results to a JSON file. This file becomes the interface between hardware and the OpenClaw agent:

import time
import json
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn

i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1115(i2c)
sensors = {
    "temperature": AnalogIn(ads, ADS.P0),
    "light": AnalogIn(ads, ADS.P1),
    "moisture": AnalogIn(ads, ADS.P2),
}

LOG_PATH = "/home/pi/sensor_data/latest.json"
CSV_PATH = "/home/pi/sensor_data/readings.csv"

while True:
    readings = {}
    for name, chan in sensors.items():
        readings[name] = {
            "voltage": round(chan.voltage, 4),
            "raw": chan.value,
            "timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
        }

with open(LOG_PATH, "w") as f:
        json.dump(readings, f, indent=2)

with open(CSV_PATH, "a") as f:
        ts = readings["temperature"]["timestamp"]
        vals = ",".join(str(readings[k]["voltage"]) for k in sensors)
        f.write(f"{ts},{vals}
")

time.sleep(60)

The JSON file always holds the latest reading. The CSV appends every sample for long-term analysis. Separating the two lets the agent check current state without parsing a growing log.

Connecting OpenClaw to the pipeline

OpenClaw can execute shell commands, read files, and schedule recurring tasks directly on the Pi. The agent workflow looks like this:

  1. A scheduled task runs the capture script at boot (or restarts it if it crashes)
  2. The agent periodically reads latest.json to check current sensor values
  3. When a reading crosses a configured threshold (soil moisture drops below 30%, temperature exceeds 35C), the agent can send an alert through a messaging channel, write an entry to a structured log, or trigger a corrective action like toggling a relay
  4. On a configurable interval, the agent pushes the accumulated CSV data to cloud storage for archival and team access

The key advantage over a raw cron job or systemd timer is that the agent can reason about the data. Instead of hard-coded threshold checks in a bash script, the agent interprets readings in context: "moisture has been declining steadily for three hours" is a different situation from "moisture spiked low for one reading and recovered," even though both cross the same numeric threshold.

For projects that already use the I2C bus for multiple sensors, the approach described in our Raspberry Pi I2C sensor bus guide applies the same pattern with smbus2 and multi-device address scanning.

AI agent processing and indexing incoming data streams

Persisting Sensor Logs in a Shared Workspace

A CSV file on a Pi's SD card is one power outage away from disappearing. Even without hardware failure, getting data off the Pi typically means SSH, scp, or pulling the card. For projects that run longer than a weekend experiment, you need off-device storage that is accessible to both agents and humans.

Several options work. You can push files to S3, sync to Google Drive, or rsync to a NAS. Each requires its own authentication setup, and none gives you a way to search or query the data without downloading it first.

Fast.io provides a workspace that handles both storage and access. The OpenClaw agent can upload CSV logs to a Fast.io workspace through the MCP server at mcp.fast.io, which exposes file operations, workspace management, and search through a standard protocol. Uploaded files are automatically indexed by Intelligence Mode, which means you can ask questions like "what was the peak temperature last Tuesday" without downloading or parsing the CSV yourself.

The practical workflow:

  1. The capture script writes sensor readings to local CSV files, rotating daily
  2. The OpenClaw agent uploads completed daily files to a Fast.io workspace
  3. Team members access the workspace through a browser or API to review data, run queries, or download files
  4. The agent retains the last 48 hours of local data as a buffer, then deletes older local files to conserve SD card space

Fast.io's plans include workspace storage, monthly AI credits, and multiple workspaces, and every org starts with a 14-day free trial. For a sensor project generating a few megabytes of CSV data per day, the included storage goes a long way.

The combination of local ADC hardware, a Python capture script, an OpenClaw agent for automation, and a cloud workspace for persistence turns a Raspberry Pi into a self-managing sensor station. The hardware reads the physical world. The agent decides what to do about it. The workspace makes the results accessible to everyone who needs them.

Frequently Asked Questions

Does Raspberry Pi have a built-in ADC?

No. Every Raspberry Pi model, from the original Pi 1 through the Pi 5, has digital-only GPIO pins that read high (3.3V) or low (0V). Reading analog sensor voltages requires an external ADC chip like the MCP3008 or ADS1115 connected via SPI or I2C.

What is the best ADC for Raspberry Pi?

It depends on the project. The MCP3008 ($4.50, 10-bit, 8 channels, SPI) is the best starter chip for most hobby projects. The ADS1115 ($14.95, 16-bit, 4 channels, I2C) is better for precision measurement and simpler wiring. The ADS1015 ($9.95) splits the difference with faster sampling at 12-bit resolution.

How do I read analog sensors with Raspberry Pi?

Connect an external ADC chip to the Pi's GPIO header using SPI or I2C, enable the interface through raspi-config, install the appropriate Python library (adafruit-circuitpython-mcp3xxx for MCP3008 or adafruit-circuitpython-ads1x15 for ADS1115), and use the library's AnalogIn class to read voltage values from each channel.

What is the difference between MCP3008 and ADS1115?

The MCP3008 uses SPI, has 8 channels, and provides 10-bit resolution (1024 distinct values) at up to 200,000 samples per second. The ADS1115 uses I2C, has 4 channels, and provides 16-bit resolution (65,536 distinct values) at up to 860 samples per second. The ADS1115 also includes a programmable gain amplifier for measuring small voltages without external amplification.

Can I connect multiple ADC chips to one Raspberry Pi?

Yes. For SPI chips like the MCP3008, each additional chip needs its own chip-select (CS) GPIO pin. For I2C chips like the ADS1115, each chip is set to a different address using the ADDR pin, supporting up to four chips (16 channels) on the same two-wire bus without additional GPIO.

What analog sensors work with a Raspberry Pi ADC?

Any sensor that outputs a variable voltage between 0V and the ADC's reference voltage. Common examples include thermistors and TMP36 temperature sensors, photoresistors (LDRs) for light measurement, capacitive soil moisture probes, potentiometers for user input, MQ-series gas sensors, and force-sensitive resistors.

Related Resources

Fastio features

Store and query your sensor data from any device

A shared workspace with a built-in MCP endpoint. Upload CSVs, query readings through Intelligence Mode, and share results with your team. Starts with a 14-day free trial.