Chapter 37

Edge Computing: Building a 24/7 Always-On Raspberry Pi Agent Node

Chapter 37: Edge Computing in Practice โ€” Complete Setup of a Raspberry Pi 24/7 Always-On Agent Node

Overview

The Raspberry Pi is one of the best platforms for an OpenClaw Headless Node. It's compact, low-power, capable of running around the clock, affordable, and equipped with rich GPIO interfaces for sensor integration. This chapter walks you step by step โ€” starting from hardware selection โ€” through configuring a Raspberry Pi as a production-grade Always-On Agent Node: always connected to your Gateway, ready to respond to Agent commands at any time, and capable of autonomous camera capture and sensor data collection.


37.1 Hardware Selection

Model RAM Recommendation Use Case
Raspberry Pi 5 (4GB) 4 GB Top pick High-frequency command execution, multiple sensors
Raspberry Pi 5 (8GB) 8 GB Flagship Local lightweight inference + Node dual purpose
Raspberry Pi 4B (4GB) 4 GB Recommended Standard Node scenarios
Raspberry Pi 4B (2GB) 2 GB Acceptable Low-load pure command execution
Raspberry Pi Zero 2W 512 MB Not recommended Too little RAM; Node.js 22 will struggle

Recommended: Raspberry Pi 4B 4GB or Raspberry Pi 5 4GB. The Pi 5 offers roughly 2-3x the performance, and its USB 3.0 bandwidth is much more comfortable for camera connectivity.

Required Accessories

- MicroSD card: 32GB+, Class 10 / A1 rated (Samsung EVO series recommended)
- Power supply: Official USB-C power adapter (Pi 4B: 15W / Pi 5: 27W)
- Cooling: Active fan or aluminum heatsink case (essential for 24/7 operation)
- Network: Wired Ethernet preferred (stability > wireless)
- Optional: USB camera (Logitech C920 / Pi Camera Module 3)

Storage Recommendation

For production use, strongly consider using an SSD instead of a MicroSD card (via USB 3.0 adapter):

# Pi 5 also supports a NVMe HAT (M.2 SSD direct connection)
# SSD lifespan is approximately 10x longer than MicroSD,
# with roughly 5x higher read/write speeds

37.2 System Configuration

Operating System Selection

OS Advantages Use Case
Ubuntu Server 24.04 LTS (ARM64) Latest packages, matches mainstream documentation Recommended; first choice for production
Raspberry Pi OS Lite (64-bit) Official optimization, best hardware compatibility When GPIO/Camera modules are needed
Debian 12 Bookworm (ARM64) Most stable Minimal-maintenance scenarios

This chapter uses Ubuntu Server 24.04 LTS ARM64 as the example.

Writing the OS Image

# Use Raspberry Pi Imager (recommended)
# Or use dd (Linux/macOS):
sudo dd if=ubuntu-24.04-preinstalled-server-arm64+raspi.img.xz \
  of=/dev/sdX bs=4M status=progress conv=fsync

In Raspberry Pi Imager, configure before writing:

First-Boot Configuration

# SSH into the device
ssh [email protected]

# Update the system
sudo apt update && sudo apt upgrade -y

# Set timezone
sudo timedatectl set-timezone America/New_York

# Configure hostname
sudo hostnamectl set-hostname openclaw-node-01

# Enable and configure firewall (allow SSH)
sudo ufw allow OpenSSH
sudo ufw enable

# Disable unnecessary services (reduce power consumption)
sudo systemctl disable bluetooth
sudo systemctl disable cups
sudo systemctl stop bluetooth cups

Memory Optimization

Edit /boot/firmware/config.txt (Ubuntu) or /boot/config.txt (Pi OS):

# Reduce GPU memory allocation (no graphical interface)
gpu_mem=16

# Enable USB boot (if using SSD)
# program_usb_boot_mode=1

37.3 Installing Node.js 22 LTS

OpenClaw Node requires Node.js 22 LTS (the current LTS release).

# Install the NodeSource setup script
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -

# Install Node.js
sudo apt install -y nodejs

# Verify installation
node --version   # v22.x.x
npm --version    # 10.x.x

Method 2: nvm (Suitable for Development Machines)

# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash

# Reload the shell
source ~/.bashrc

# Install Node.js 22
nvm install 22
nvm use 22
nvm alias default 22

Verify the Environment

node --version
# v22.14.0

npm --version
# 10.9.2

# Verify ARM64 architecture
node -e "console.log(process.arch)"
# arm64

37.4 Installing OpenClaw Node

# Install the OpenClaw CLI globally (includes the node subcommand)
sudo npm install -g @openclaw/cli

# Verify installation
openclaw --version
# openclaw 4.2.1

# Initialize Node configuration
openclaw node init

openclaw node init guides you through:

  1. Enter the Gateway address (e.g., 192.168.1.100 or mygateway.ts.net)
  2. Set the node display name (e.g., Pi Node - Living Room)
  3. Choose the capabilities to declare (Headless mode defaults to system.run)
  4. Generate and save the node ID

The configuration file is saved at ~/.openclaw/node.json by default:

{
  "nodeId": "node-a1b2c3d4",
  "displayName": "Pi Node - Living Room",
  "gateway": {
    "host": "192.168.1.100",
    "port": 18789,
    "tls": false
  },
  "capabilities": ["system.run", "system.which"],
  "reconnect": {
    "enabled": true,
    "initialDelay": 5,
    "maxDelay": 300,
    "multiplier": 2
  }
}

37.5 Remote Connection Commands

Basic Connection Command

# Run in foreground (for testing)
openclaw node run \
  --host 192.168.1.100 \
  --port 18789 \
  --display-name "Pi Node - Living Room"

# Run with configuration file (recommended)
openclaw node run --config ~/.openclaw/node.json

# Connect to a Gateway at a Tailscale address
openclaw node run \
  --host mygateway.ts.net \
  --port 18789 \
  --display-name "Raspberry Pi 4B" \
  --tls

# Specify additional capabilities
openclaw node run \
  --host 192.168.1.100 \
  --port 18789 \
  --display-name "Pi Camera Node" \
  --capabilities system.run,system.which

Connection Verification

On a successful connection, the Gateway outputs:

[Gateway] Node connected: Pi Node - Living Room (node-a1b2c3d4)
[Gateway] Capabilities registered: system.run, system.which
[Gateway] Node status: pending (awaiting approval)

Approve on the Gateway host:

openclaw devices list
# ID          DISPLAY NAME           PLATFORM   STATUS
# req-x1y2    Pi Node - Living Room  headless   pending

openclaw devices approve req-x1y2
# โœ“ Device approved: Pi Node - Living Room

37.6 Architecture Diagram: Gateway in the Cloud, Raspberry Pi on-Premises

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   Cloud (AWS)                        โ”‚
โ”‚                                                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚   OpenClaw  โ”‚    โ”‚         Gateway             โ”‚ โ”‚
โ”‚  โ”‚   Agent     โ”‚โ—„โ”€โ”€โ–บโ”‚  (Inference + Routing +     โ”‚ โ”‚
โ”‚  โ”‚  (LLM calls)โ”‚    โ”‚   WebSocket) port: 18789    โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                                โ”‚ WebSocket (TLS)     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚
                    Internet / Tailscale VPN
                                 โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Local Network                     โ”‚
โ”‚                                โ”‚                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚              Raspberry Pi 4B / 5                โ”‚ โ”‚
โ”‚  โ”‚                                                 โ”‚ โ”‚
โ”‚  โ”‚   openclaw node run (role: "node")              โ”‚ โ”‚
โ”‚  โ”‚                                                 โ”‚ โ”‚
โ”‚  โ”‚   Capabilities:                                 โ”‚ โ”‚
โ”‚  โ”‚   โœ“ system.run  โ† Shell command execution       โ”‚ โ”‚
โ”‚  โ”‚   โœ“ system.which                                โ”‚ โ”‚
โ”‚  โ”‚                                                 โ”‚ โ”‚
โ”‚  โ”‚   Optional extensions:                          โ”‚ โ”‚
โ”‚  โ”‚   โœ“ USB camera โ†’ camera.snap                   โ”‚ โ”‚
โ”‚  โ”‚   โœ“ Temp/humidity sensor (DHT22) โ†’ sensor.read โ”‚ โ”‚
โ”‚  โ”‚   โœ“ GPIO control โ†’ gpio.write                  โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Workflow:
User โ†’ Control UI โ†’ Gateway โ†’ Agent Inference โ†’
Tool Call (system.run) โ†’ Route to Raspberry Pi โ†’
Execute command locally โ†’ Return result โ†’ Agent โ†’ User

37.7 systemd Service Configuration for Auto-Start

Create a Dedicated User (Security Best Practice)

# Create a no-shell system user
sudo useradd --system --no-create-home --shell /usr/sbin/nologin openclaw-node

# Create configuration directories
sudo mkdir -p /etc/openclaw /var/log/openclaw
sudo chown openclaw-node:openclaw-node /var/log/openclaw

# Copy configuration file
sudo cp ~/.openclaw/node.json /etc/openclaw/node.json
sudo chown openclaw-node:openclaw-node /etc/openclaw/node.json
sudo chmod 640 /etc/openclaw/node.json

systemd Service Unit File

Create /etc/systemd/system/openclaw-node.service:

[Unit]
Description=OpenClaw Agent Node
Documentation=https://docs.openclaw.ai/nodes
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5

[Service]
Type=simple
User=openclaw-node
Group=openclaw-node

# Executable path (confirm with: which openclaw)
ExecStart=/usr/bin/openclaw node run --config /etc/openclaw/node.json

# Working directory
WorkingDirectory=/var/lib/openclaw

# Environment variables (do NOT place secrets here; use EnvironmentFile)
Environment=NODE_ENV=production
Environment=LOG_LEVEL=info
EnvironmentFile=-/etc/openclaw/node.env

# Restart policy
Restart=on-failure
RestartSec=10s

# Log output
StandardOutput=append:/var/log/openclaw/node.log
StandardError=append:/var/log/openclaw/node-error.log

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/var/lib/openclaw /var/log/openclaw /etc/openclaw
AmbientCapabilities=

# Resource limits
LimitNOFILE=65536
MemoryMax=512M

[Install]
WantedBy=multi-user.target

Environment Variable File

Create /etc/openclaw/node.env (mode 600):

# Node-specific environment variables (if needed)
OPENCLAW_NODE_LOG_LEVEL=info
OPENCLAW_NODE_RECONNECT_ENABLED=true
sudo chown root:openclaw-node /etc/openclaw/node.env
sudo chmod 640 /etc/openclaw/node.env

Create the Working Directory

sudo mkdir -p /var/lib/openclaw
sudo chown openclaw-node:openclaw-node /var/lib/openclaw

Enable and Start the Service

# Reload systemd configuration
sudo systemctl daemon-reload

# Enable auto-start on boot
sudo systemctl enable openclaw-node

# Start the service immediately
sudo systemctl start openclaw-node

# Check service status
sudo systemctl status openclaw-node

Verify the Service is Running

# Stream live logs
sudo journalctl -u openclaw-node -f

# View log file
sudo tail -f /var/log/openclaw/node.log

# Typical successful startup log:
# [2026-04-26 09:00:00] OpenClaw Node v4.2.1 starting...
# [2026-04-26 09:00:01] Connecting to Gateway: 192.168.1.100:18789
# [2026-04-26 09:00:02] WebSocket connected
# [2026-04-26 09:00:02] Capabilities declared: system.run, system.which
# [2026-04-26 09:00:03] Node status: online (node-a1b2c3d4)

37.8 Camera Integration and Automated Reporting

Hardware Preparation

USB Camera (Logitech C920 recommended):

# Check camera detection
lsusb | grep -i logitech
# Bus 002 Device 003: ID 046d:082d Logitech, Inc. HD Pro Webcam C920

ls /dev/video*
# /dev/video0  /dev/video1

# Install ffmpeg
sudo apt install -y ffmpeg v4l-utils

# Test a photo capture
ffmpeg -f v4l2 -i /dev/video0 -frames:v 1 /tmp/test.jpg

Raspberry Pi Camera Module 3 (CSI interface):

# Enable CSI camera on Ubuntu
echo "dtoverlay=imx708" | sudo tee -a /boot/firmware/config.txt

# On Pi OS, use libcamera
sudo apt install -y libcamera-apps
libcamera-jpeg -o /tmp/test.jpg --width 1920 --height 1080

Adding camera.snap Capability to the Node

Edit /etc/openclaw/node.json:

{
  "nodeId": "node-a1b2c3d4",
  "displayName": "Pi Camera Node",
  "gateway": {
    "host": "192.168.1.100",
    "port": 18789
  },
  "capabilities": ["system.run", "system.which", "camera.snap"],
  "camera": {
    "device": "/dev/video0",
    "snapCommand": "ffmpeg -f v4l2 -i /dev/video0 -frames:v 1 {output} -y",
    "outputDir": "/tmp/openclaw-camera"
  }
}

Scheduled Automatic Photo Reporting

Create a Cron task (via Control UI):

# Take a photo every 30 minutes
*/30 * * * * node_invoke camera.snap --node node-a1b2c3d4 --upload-to memory

Or trigger a custom script via system.run:

# /usr/local/bin/camera-snap.sh
#!/bin/bash
OUTPUT="/tmp/openclaw-camera/snap-$(date +%Y%m%d-%H%M%S).jpg"
mkdir -p /tmp/openclaw-camera
ffmpeg -f v4l2 -i /dev/video0 -frames:v 1 "$OUTPUT" -y -loglevel quiet
echo "$OUTPUT"

37.9 Sensor Data Collection (GPIO/I2C)

DHT22 Temperature and Humidity Sensor

# Install Python GPIO library
sudo apt install -y python3-pip
pip3 install adafruit-circuitpython-dht

# Read script: /usr/local/bin/read-dht22.py
#!/usr/bin/env python3
import adafruit_dht
import board
import json
import sys

dht = adafruit_dht.DHT22(board.D4)  # GPIO4

try:
    temperature = dht.temperature
    humidity = dht.humidity
    result = {
        "temperature_c": round(temperature, 1),
        "temperature_f": round(temperature * 9/5 + 32, 1),
        "humidity_percent": round(humidity, 1),
        "timestamp": __import__('time').time()
    }
    print(json.dumps(result))
except Exception as e:
    print(json.dumps({"error": str(e)}), file=sys.stderr)
    sys.exit(1)

The Agent calls this via system.run:

python3 /usr/local/bin/read-dht22.py
# {"temperature_c": 24.5, "temperature_f": 76.1, "humidity_percent": 58.3, "timestamp": 1745625600}

BMP280 Barometric Pressure Sensor (I2C)

# Enable I2C
sudo raspi-config nonint do_i2c 0
# Or edit /boot/firmware/config.txt and add: dtparam=i2c_arm=on

# Detect I2C devices
i2cdetect -y 1
# 77: BMP280 default address

pip3 install adafruit-circuitpython-bmp280
#!/usr/bin/env python3
import adafruit_bmp280
import board
import busio
import json

i2c = busio.I2C(board.SCL, board.SDA)
bmp280 = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)
bmp280.sea_level_pressure = 1013.25

print(json.dumps({
    "pressure_hpa": round(bmp280.pressure, 2),
    "altitude_m": round(bmp280.altitude, 1),
    "temperature_c": round(bmp280.temperature, 1)
}))

37.10 Power Consumption Optimization

CPU Frequency Scaling

# Check current frequency
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

# Set conservative governor (good for sustained light loads)
echo "conservative" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# Permanent setting (edit /boot/firmware/config.txt)
# arm_freq=1500  # Pi 4B default is 1800; lowering to 1500 saves ~15% power
# over_voltage=0

Disable Unused Hardware

# Disable Wi-Fi (when using wired ethernet)
sudo rfkill block wifi

# Disable Bluetooth
sudo rfkill block bluetooth

# Turn off HDMI output (saves ~25mA when no monitor is attached)
# Add to /etc/rc.local:
# /usr/bin/tvservice -o

# Disable USB power (Pi 4B, when no USB devices are needed)
# echo '1-1' | sudo tee /sys/bus/usb/drivers/usb/unbind

Typical Power Consumption Reference (Pi 4B)

Configuration Typical Power
Full load (1.8GHz + USB devices) ~6.4W
Idle (Wi-Fi disabled, no USB) ~2.7W
Optimized (underclocked + HDMI off) ~2.1W
Deep sleep (not suitable for Always-On) ~1.4W

37.11 Common Troubleshooting

Issue 1: Node Frequently Disconnects and Reconnects

# Check network stability
ping -c 100 192.168.1.100 | tail -5
# If packet loss > 1%, investigate network hardware first

# Check if Gateway is overloaded
openclaw gateway status

# Increase reconnect backoff time (prevent storm)
# Edit node.json:
# "reconnect": { "initialDelay": 10, "maxDelay": 600, "multiplier": 3 }

Issue 2: system.run Execution Fails

# Check executable paths
which python3 ffmpeg bash

# Test permissions as the openclaw-node user
sudo -u openclaw-node /usr/bin/python3 -c "print('ok')"

# If /dev/video0 access is needed, add user to the video group
sudo usermod -aG video openclaw-node
sudo systemctl restart openclaw-node

Issue 3: Out of Memory (OOM)

# Check memory usage
free -h
sudo journalctl -k | grep -i "oom\|killed"

# Node process already has MemoryMax=512M in the systemd unit file

# If system-wide memory is insufficient, add swap
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Issue 4: Node Does Not Appear in Gateway

# Confirm firewall allows outbound port 18789
sudo ufw status

# Test TCP connectivity
nc -zv 192.168.1.100 18789

# Check Node logs
sudo journalctl -u openclaw-node --since "5 minutes ago"

# Common causes: wrong Gateway address, TLS configuration mismatch

Issue 5: Camera Permission Denied

# Check /dev/video0 permissions
ls -la /dev/video0
# crw-rw----+ 1 root video 81, 0 Apr 26 09:00 /dev/video0

# Confirm user is in the video group (service restart required to take effect)
sudo usermod -aG video openclaw-node
sudo systemctl restart openclaw-node
groups openclaw-node
# openclaw-node : openclaw-node video

37.12 Updates and Maintenance

Updating OpenClaw Node

# Check current version
openclaw --version

# Update to the latest stable version
sudo npm update -g @openclaw/cli

# Restart the service after update
sudo systemctl restart openclaw-node

Log Rotation Configuration

Create /etc/logrotate.d/openclaw-node:

/var/log/openclaw/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    postrotate
        systemctl kill --signal=USR1 openclaw-node.service 2>/dev/null || true
    endscript
}

37.13 Summary

With the configuration covered in this chapter, your Raspberry Pi is now:

Combined with the capability matrix introduced in Chapter 36, you now have complete command of the full technical path for integrating physical devices into OpenClaw Agent. The next chapter focuses on deep usage of the Control UI.


Next Chapter: Chapter 38 โ€” Control UI Deep Dive: Configuration Editing, Live Logs, Approval Management, and Dream Diary

Rate this chapter
4.7  / 5  (3 ratings)

๐Ÿ’ฌ Comments