ESP32 Harvest Monitor with CAM & GPS — ESP32 simulation

Dual-ESP32 build: a DevKit V1 dashboard reading DHT22, sound and GPS on a 2.8" ILI9341, plus an ESP32-CAM sending mock vision results over UART.

An interactive ESP32 circuit simulation you can run free in your browser on Velxio, by seabecyber.

Components

Sketch code

/*
 * Mopane Monitor - MAIN node (ESP32 DevKit V1)
 *
 * Sensors : DHT22 (D4), Grove sound sensor (D34), Grove GPS (Serial2: RX2/TX2)
 * Link    : ESP32-CAM results arrive on Serial1 (D25 = RX, D26 = TX)
 * Display : ILI9341 2.8" on hardware SPI (display only, touch pins unused)
 *
 * Camera link protocol (one line per second from the CAM board):
 *     CAM,<detected 0/1>,<stage 0-2>,<confidence 0-100>
 *     stage: 0 = no worms, 1 = early growth, 2 = advanced growth
 *
 * Reply to the CAM (one line per second, over D26):
 *     MAIN,<state 0-2>,<confidence 0-100>,<uncertain 0/1>
 *
 * Fusion: optical (60 %) + acoustic (40 %) weighted vote. Low confidence is
 * shown as UNCERTAIN, never as a confirmed harvest recommendation.
 * If the camera is offline the node falls back to acoustic-only.
 */

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <DHT.h>
#include <TinyGPSPlus.h>

// ----------------------------------------------------------------- Pins
#define TFT_CS    5
#define TFT_DC    32
#define TFT_RST   33
// SCK = D18, MOSI = D23, MISO = D19 (default SPI, not listed in code)

#define DHT_PIN   4
#define DHT_TYPE  DHT22
#define MIC_PIN   34

#define GPS_RX    16   // GPS TX -> D16 (RX2)
#define GPS_TX    17   // GPS RX <- D17 (TX2)

#define CAM_RX    25   // CAM TX -> D25
#define CAM_TX    26   // CAM RX <- D26

// ----------------------------------------------------------------- Tuning
const uint32_t DHT_MS       = 2000;
const uint32_t MIC_MS       = 200;
const uint32_t SCREEN_MS    = 500;
const uint32_t CAM_TIMEOUT  = 5000;   // ms without a CAM line = offline
const float    MIC_LOW      = 10.0f;  // % below this: no feeding activity
const float    MIC_HIGH     = 40.0f;  // % above this: vigorous activity
const float    UNCERTAIN_BELOW = 70.0f;

// ----------------------------------------------------------------- Objects
Adafruit_ILI9341 tft(TFT_CS, TFT_DC, TFT_RST);
DHT dht(DHT_PIN, DHT_TYPE);
TinyGPSPlus gps;

// ----------------------------------------------------------------- State
float tempC = NAN, hum = NAN;

float micLevel = 0;           // 0-100 %
float micBaseline = -1;

struct CamData {
  int  detected = 0;
  int  stage    = 0;
  int  conf     = 0;
  uint32_t lastMs = 0;
} cam;

int   acStage = 0;   float acConf = 0;   // acoustic-only result
int   opStage = 0;   float opConf = 0;   // optical-only result
int   fusedStage = 0; float fusedConf = 0;
bool  camOnline = false;
bool  uncertain = true;

uint32_t tDht = 0, tMic = 0, tScreen = 0, tStatus = 0;
const uint32_t STATUS_MS = 1000;      // how often the result is sent back to the CAM
char camBuf[48];
uint8_t camLen = 0;

const char* stageName(int s) {
  return s == 0 ? "No worms" : (s == 1 ? "Early growth" : "Advanced growth");
}

// ----------------------------------------------------------------- Display helpers
void printLine(int x, int y, const char* s, uint16_t color, uint8_t size = 1, int width = 24) {
  char buf[40];
  snprintf(buf, sizeof(

More projects by seabecyber