⊞ Desktop C:\Projects\SmartPlantBuddy\case-study.exe

IoT · sensing · data · MSc Design Engineering, Imperial College London

Smart Plant Buddy

"Is my green thumb not so green?" An ESP32 plant monitor that reads soil, light, temperature and humidity, logs them to the cloud, and shows a little face on an OLED screen so the plant can tell you how it feels.

Role
Solo: hardware, firmware, cloud, dashboard, analysis
Module
Sensing & Internet of Things, Dyson School of Design Engineering
Date
December 2025
Stack
ESP32 (C++), Firebase RTDB, JavaScript + Chart.js, Python
ESP32 on a breadboard wired to sensors in a potted Polyscias plant, with the OLED display glowing
693readings over 7 days, 100% uploaded
95%mood classifier accuracy (n=40 checks)
237msaverage upload latency; dashboard < 2s
£19hardware cost, 84% cheaper than a £129 smart pot
🌱 01_problem.txt
01

Plants can't say what they need

Most houseplants don't die from neglect. They die because their owners can't tell what they need or when. People end up watering too much or too little, and the existing smart pots are either expensive or just show numbers you have to interpret yourself.

Aim: give the plant a voice by combining multi-sensor sensing, cloud logging and expressive feedback, so that plant care is easier to read and more fun to do.

🧩 02_system_design/
02

Three-tier architecture

The sensing layer is an ESP32 polling four sensors. The network layer sends HTTP POSTs to Firebase every 15 minutes, with WebSockets for live updates. The application layer is a web dashboard. The OLED handles feedback at the edge, so the face updates instantly without waiting on the cloud.

Diagram: sensing layer (ESP32 + sensors + OLED) to network layer (WiFi, HTTP, WebSocket) to Firebase and the web dashboard
Data flow: sensors → ESP32 → WiFi → Firebase → dashboard, with local OLED feedback

Bill of materials

PartPinCost
ESP32-WROOM (240 MHz, WiFi)—£8
Resistive soil moistureGPIO34£2
LDR + 10 kΩ dividerGPIO35£1
DHT11 temp / humidityGPIO4£3
SSD1306 OLED 128×64 (I²C)GPIO14/15£5
Total£19
Circuit schematic of the ESP32 with soil sensor, LDR, DHT11 and OLED
Circuit schematic
📡 03_sensing.cpp
03

Calibrating the senses

SOIL MOISTURE

2-point calibration

Calibrated between dry air and full submersion. For my Polyscias: <1500 is dry, 1500–2400 is healthy, and >3500 only happens right after watering. I checked it against a two-day drying cycle.

LIGHT

LDR voltage divider

Covered it reads about 120, indirect daylight 800–2500, and a bright window 3000+. The logs show a clear day/night pattern that peaks around 1–3pm.

TEMP + HUMIDITY

DHT11

Accurate to ±2 °C / ±5% RH, which is fine indoors. I checked it against a thermometer, and the firmware respects the sensor's 2-second minimum between reads.

Every reading averages 10 samples to smooth out ADC noise, especially the WiFi interference during transmits. Each log is about 150 bytes of JSON stored under /plants/plant1/logs/{id} and indexed by timestamp, so "last 24h / 3 days / week" queries stay fast.

Serial monitor output showing soil, light, temperature, humidity and mood=happy readings
Serial monitor during calibration
😊 04_mood.h
04

Giving it a face

A rule-based classifier turns the readings into a mood. Critical states are checked first so the plant never shows two moods that contradict each other:

String getMood() {
  if (soilRaw < SOIL_DRY_THRESH)  return "thirsty";
  if (soilRaw > SOIL_WET_THRESH)  return "overwatered";
  if (tempC > TEMP_HOT_THRESH)    return "hot";
  if (lightRaw < LIGHT_LOW_THRESH) return "dark";
  return "happy";
}

The OLED redraws every 2 seconds with a title bar, a big emoji-style face and a compact sensor summary:

Happy ^ ^Thirsty O OHot > <Drowning @ @OK :—

In a small pilot (N=5), everyone understood the faces without being told what they meant. People checked the OLED 80% of the time, compared with 40% for an earlier phone-only prototype.

Hand holding the OLED display showing the Smart Plant Buddy happy face
The OLED showing "happy"
📈 05_analysis.py
05

What a week of data showed

I logged 693 readings at 15-minute intervals. Soil moisture follows a zigzag: it jumps to about 3800–4000 after watering, then drains over 60–80 hours. Light is almost perfectly diurnal. Temperature and humidity barely move indoors.

Four stacked time-series charts of soil moisture, light, temperature and humidity over 7 days
7-day time series: soil drying cycles, daily light rhythm, stable indoor climate

Combining sensors made it more useful. A sharp soil jump (>800 ADC) plus a small humidity bump detected all 7 watering events with zero false positives. The strong soil–temperature link also makes predicting when to water feel within reach.

🖥️ 06_dashboard.html
06

A friendly dashboard

It's built in plain JavaScript, Chart.js and the Firebase Web SDK, with no framework so I had full control over layout and performance. It has live sensor cards, a big mood emoji, time filters, a carousel of four charts, live stats and a CSV export.

  • Downsampled ~700 points to ~200 before plotting, which cut render time with no visible loss.
  • Species profiles (Polyscias, succulent, Musa, fern) change the thresholds and the care advice.
  • WebSocket updates show up in about 1.8s, and the first load takes under 2s.
Dashboard showing plant type selector, mood emoji, live readings, care tips and a soil moisture chart
Live dashboard with care tips for the selected species
Dashboard overview with all sensor charts, mood pie chart, statistics and correlations
Overview: every sensor, the mood breakdown and live statistics
✅ 07_evaluation.csv
07

Did it work?

MetricTargetAchieved
Data completeness> 95%100% (693/693)
Upload latency< 500 ms237 ms (P95 312 ms)
Dashboard load< 3 s1.8 s
OLED response< 1 s0.1 s
Mood accuracy> 85%95%
Uptime> 95%99.7% (one 28 s WiFi drop)

Challenges

NOISE

WiFi interference

Soil readings jittered whenever the board transmitted. A 10-sample moving average fixed it.

HARDWARE

Probe corrosion

After about two weeks, copper oxide started skewing the resistive probe. I cleaned the probes or swapped them for spares.

PERFORMANCE

Laggy charts

Plotting every point made Chart.js sluggish, so I downsample before plotting.

Next steps

Automatic watering, a camera for checking leaf health visually, more species profiles, and proper security: Firebase Auth rules, credentials stored in NVS and certificate pinning, since the prototype uses open rules and hardcoded WiFi credentials.

▶ demo.mp4

See it running