Going Online — From Serial Port to Cloud API
Yesterday the ESP32 printed sensor readings to a serial port. Today it posts them to the internet.
Session 1: WiFi and HTTP
Updated the ESP32 firmware to connect to WiFi on boot and POST JSON to a Flask server running on the Raspberry Pi every 30 seconds:
{"temperature": 23.5, "humidity": 48.2}
The Pi runs a minimal Flask app on port 5000 that receives these readings and stores them in a SQLite database. Three API endpoints:
POST /reading— the ESP32 writes here every 30 secondsGET /reading— returns the latest readingGET /history?hours=N— returns all readings from the last N hours
Every request requires an API key. I forgot this on the first firmware deploy — the ESP32 was happily POSTing and getting 401 errors back. Had to recompile and reflash. The kind of mistake you only make once.
The compile-on-laptop, flash-via-Pi pipeline works well: compile with PlatformIO on WSL2, SCP the binary to the Pi, run esptool over SSH. About 30 seconds end to end.
Session 2: Infrastructure
With data flowing, I built out the infrastructure to make this remotely accessible and resilient.
Cloudflare Tunnel
The Pi sits behind a home router with no port forwarding. I set up a Cloudflare Tunnel so the Flask API is accessible at lab.egc.land from anywhere. The tunnel runs as a systemd service and connects to Cloudflare’s edge via QUIC — four connections to the London data centre.
systemd services
Two services configured to start on boot:
- lab-server.service — the Flask API on port 5000
- cloudflared-lab.service — the Cloudflare Tunnel
Both restart on failure. If the Pi loses power and comes back, everything is running again within seconds.
SSH key authentication
Set up SSH key auth from my laptop to the Pi. This is essential because Claude Code’s Bash tool has no TTY for interactive password prompts — key-based auth is the only option for automated access.
Session 3: Documentation
Rewrote the project’s CLAUDE.md file from a basic build-instructions file into a complete lab infrastructure reference. This file serves as the “brain” for Claude Code — it contains everything Claude needs to know about the system: architecture, API endpoints, SSH access patterns, network details, and accumulated lessons.
Also packaged up the source code and documentation for my project partner in San Francisco.
The architecture so far
DHT22 sensor
│
▼
ESP32 (reads every 30s, POSTs JSON over WiFi)
│
▼
Raspberry Pi
├── Flask server :5000 (receives readings, serves API)
├── SQLite database (all sensor data)
└── Cloudflare Tunnel → lab.egc.land
The first confirmed reading through the full pipeline: 20.3°C, 43.2% humidity.
The research plan
With the infrastructure working, we wrote the formal research plan. The target: somatic embryogenesis in mint.
Somatic embryogenesis (SE) is the process of reprogramming differentiated plant cells to form embryos without fertilisation. It’s more complex than standard micropropagation but the right choice for two reasons:
-
It’s genuinely interesting biology. The existing literature on mint SE is thin. Protocol development is notoriously empirical — dozens of interacting variables (auxin type, concentration, cytokinin type, concentration, explant type, light regime, temperature, sucrose level, pH). Most published protocols were found by varying one factor at a time over months. This is exactly the kind of problem where Claude’s systematic approach and perfect memory across experimental rounds adds real value.
-
It converges with automation. Standard micropropagation requires a human with a scalpel cutting nodes — inherently manual. Somatic embryos form in liquid suspension culture. Liquids can be pumped, filtered, dosed, and moved by machines. When human intervention becomes the bottleneck, SE is the path that lets us replace hands with pumps and valves.
The plan has four phases: get a callus (weeks 1-2), induce SE (weeks 2-6), germinate embryos into plantlets (weeks 6-10), and automate only when the biology demands it. Claude designs each protocol round based on literature and previous results.
This plan would evolve within days. Once we had real sensor data showing how the room actually behaved, a more promising first research target emerged — but I’m getting ahead of myself.
The budget
Total equipment cost so far: £434.42. That includes the Raspberry Pi, ESP32, DHT22 sensor, pressure cooker, still air box, and lab consumables. The entire monitoring infrastructure — sensor chain, server, API, Cloudflare tunnel, SSH access — cost less than a decent dinner.
Challenges
Not everything went smoothly:
- USB cable: The first cable was charge-only. The ESP32 powered on but was invisible to the host. Classic.
- Wrong gateway IP: Static IP config used 192.168.1.1 as gateway instead of .254. WiFi connected but no internet. Fixed with nmcli.
- Cloudflare bot blocking: Claude’s programmatic fetch gets blocked by Cloudflare’s bot protection, even on the free plan with all settings disabled. Permanent architectural decision: SSH + localhost curl instead of hitting the public URL.
- Baud rate: 460800 caused the chip to stop responding. Dropped to 115200.
- Port conflict: Manually started Flask process held port 5000 when we tried to start the systemd service. Had to find and kill the old PID first.
- Missing API key: The ESP32 firmware was happily POSTing without the API key, getting 401 errors back. Required a recompile and reflash.
Lessons
- Always include API authentication on every request — including the ESP32’s POST URL. Missing the API key on the first firmware deploy required a full recompile and reflash cycle.
- If a service was previously run manually (e.g.,
python3 app.py), the old process holds the port. Starting the systemd service will crash-loop with “Address already in use.” Always check for and kill old processes first. - The Pi user is
daniel, the WSL2 user isdanie. Small difference, easy to mix up, causes SSH failures. - A £434 home lab with an AI director can replicate the architecture described in Nature papers about million-pound autonomous labs. The intelligence is in the software, not the hardware.