Back to Projects

    Luluthi

    Wireless soil monitoring with real-time alerts

    Hardware design · Firmware · Full-stack developmentApril 2025Active
    6Nodes Deployed
    4 moField Tested
    0False Alerts
    <$25Per Node

    What I Built

    I kept killing my plants. Not out of neglect, but from guessing. I would check the soil by hand, assume it was dry or wet enough, and still end up overwatering or letting plants dry out.

    Most moisture sensors I found were either unreliable, too expensive ($30-100 per node), or lacked conenctivity to my phone. So I designed my own: a distributed IoT system with wireless sensor nodes, a central gateway, and a cloud dashboard that tells me exactly when each plant needs water.

    The goal was a system I'd trust and use every day, not a prototype that sits in a drawer.

    System Architecture

    Luluthi System ArchitectureThree-layer IoT architecture diagram showing ESP32 sensing nodes communicating via BLE to a Raspberry Pi gateway, which connects via HTTPS to a cloud web platform with Node.js API, PostgreSQL, and React dashboard.SENSINGGATEWAYCLOUDESP32 NodeSoil Moisture SensorStatus LEDBLE Radio× n sensor nodesLow-power soil data acquisitionRaspberry PiBLE ↔ Wi-Fi BridgeData AggregationLocal BufferingBLE aggregation & internet uplinkWeb PlatformNode.js APIPostgreSQLReact DashboardStorage, analytics & visualizationBLEHTTPS

    The system has three layers. ESP32-based sensor nodes sample soil moisture and broadcast readings over BLE. A Raspberry Pi gateway picks up those advertisements, aggregates data, and pushes it to a cloud API over Wi-Fi. The web app built with Next.js and React. It displays moisture levels and fires push notifications when a plant drops below its threshold.

    I chose BLE over Wi-Fi at the sensor level because of power draw. BLE advertising is much more energy efficient than Wi-Fi. The gateway handles all the networking complexity, which keeps the firmware dead simple and the node cheap.

    Hardware

    Each sensor node is an ESP32-C3 wired to a capacitive soil moisture probe inside a 3D-printed PLA enclosure. The whole BOM comes in under $25.

    • ESP32-C3 over nRF52840 Half the cost, integrated BLE, and good enough power draw to support peripherals.
    • Capacitive sensing over resistive No exposed metal in the soil means no galvanic corrosion. Tradeoff: requires per-soil-type calibration since different substrates have different dielectric constants.
    • BLE advertising over Wi-Fi Nodes pair with gateways over BLE. Each node will trasmit its unique ID, moisture reading, and battery voltage to the gateway over BLE. Keeping the Wi-Fi radio off saves us battery.
    • PETG enclosure via FDM printing Printing on my home printer with PETG. Iteration cycles are quick and will work well in UV for outdoor deployment. Future waterproof design will keep it protected during watering.

    ESP32-C3 sensor node PCB prototype

    Custom PCB with ESP32-C3, capacitive moisture sensor interface, and USB-C power

    Complete sensor node with capacitive moisture probe

    Assembled node with capacitive probe probe sits in soil, enclosure stays above surface

    Software

    The web dashboard is the primary interface. It's built with Next.js and React, backed by PostgreSQL, and hosted on Vercel. Each plant has a detail view with real-time moisture readings, a 30-day trend chart, and configurable alert thresholds.

    The gateway runs a Python service on a Raspberry Pi that continuously scans for BLE advertisements. When it picks up a reading, it validates the packet structure, attaches a timestamp, and POSTs it to a REST API. If the network is down, readings are buffered locally and flushed when connectivity returns.

    Push notifications use a threshold-based system: when a plant's moisture drops below its configured minimum for two consecutive readings (to avoid single-sample noise), the backend fires a notification to all subscribed devices.

    Results

    I deployed six nodes across my apartment and ran the system for 2 months straight. Moisture readings consistently predicted visible plant stress 23 days before wilting. Validated against manual soil checks.

    The real test was handing it to friends. They started checking the dashboard on their own and watering based on the alerts. That's when I knew the UX was actually working.

    Biggest lessons: BLE advertising range is heavily affected by soil moisture (wet soil attenuates the signal), calibration curves need to be per-soil-type not per-sensor.

    Sensor node powered on with status LEDs active

    Node in active operation blue LED indicates successful BLE transmission