Smart Agriculture Monitor + AI Crop Health Advisor (C++ + Raspberry Pi Project)
In this blog, we'll walk through building a Smart Agriculture Monitoring System combined with an AI-based Crop Health Advisor, using C++ and Raspberry Pi.
We'll focus on actual hardware integration (not simulation!) by connecting real sensors through the Raspberry Pi's GPIO and SPI interfaces.
The project is divided into two major parts:
-
1. Smart Agriculture Monitor (sensor_monitor): Collects real-time environmental data (temperature, humidity, soil moisture, light).
-
2. AI Crop Health Advisor (ai_advisor): Analyzes recent sensor data and suggests care actions like watering or adjusting light conditions.
Part 1: Sensor Integration with Raspberry Pi (sensor_monitor)
We are upgrading from simulated values to actual sensor readings:
-
DHT11 Sensor for humidity and temperature.
-
MCP3008 ADC (via SPI) for analog soil moisture sensor and LDR (Light Dependent Resistor).
Let's get started!
DHT11 Sensor Integration
There is no standard C++ DHT11 library for the Pi, so we write a minimal GPIO-based DHT11 reader.
sensor_monitor/DHT11.hpp:
#ifndef DHT11_HPP
#define DHT11_HPP
#include <wiringPi.h>
#include <iostream>
#include <cstdint>
#define MAX_TIMINGS 85
#define DHT_PIN 7 // WiringPi pin (GPIO4)
bool readDHT11(float &temperature, float &humidity) {
uint8_t bits[5] = {0};
uint8_t last_state = HIGH;
int bit_idx = 0;
pinMode(DHT_PIN, OUTPUT);
digitalWrite(DHT_PIN, LOW);
delay(18);
digitalWrite(DHT_PIN, HIGH);
delayMicroseconds(40);
pinMode(DHT_PIN, INPUT);
for (int i = 0; i < MAX_TIMINGS; ++i) {
int count = 0;
while (digitalRead(DHT_PIN) == last_state) {
++count;
delayMicroseconds(1);
if (count == 255) break;
}
last_state = digitalRead(DHT_PIN);
if (count == 255) break;
if ((i >= 4) && (i % 2 == 0)) {
bits[bit_idx / 8] <<= 1;
if (count > 50) bits[bit_idx / 8] |= 1;
++bit_idx;
}
}
if (bit_idx >= 40) {
uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3];
if (bits[4] == (sum & 0xFF)) {
humidity = bits[0];
temperature = bits[2];
return true;
}
}
return false;
}
#endif
Updating sensor_monitor/main.cpp
Now, let's use real DHT11 data instead of simulated values.
sensor_monitor/main.cpp:
#include "DHT11.hpp"
#include "sensors.hpp" // For MCP3008 reading
#include "logger.hpp" // For logging to database
int main() {
wiringPiSetup();
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) < 0) {
std::cerr << "SPI setup failed.\n";
return 1;
}
while (true) {
float temp = 0, humid = 0;
bool success = readDHT11(temp, humid);
if (!success) {
std::cerr << "Failed to read DHT11 data.\n";
sleep(2);
continue;
}
int soil = readAnalog(0); // Moisture sensor on channel 0
int light = readAnalog(1); // LDR on channel 1
std::cout << "Temp: " << temp << "°C, Humidity: " << humid
<< "%, Soil: " << soil << ", Light: " << light << std::endl;
logToDatabase(temp, humid, soil, light);
sleep(10); // Read every 10 seconds
}
return 0;
}
MCP3008 Integration for Analog Sensors
The MCP3008 ADC allows us to connect analog sensors like soil moisture and LDR to the Pi via SPI.
sensor_monitor/sensors.hpp:
#ifndef SENSORS_HPP
#define SENSORS_HPP
#include <wiringPiSPI.h>
#include <iostream>
#define SPI_CHANNEL 0
#define SPI_SPEED 1000000 // 1MHz
int readAnalog(int channel) {
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Start bit
buffer[1] = (8 + channel) << 4;
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int value = ((buffer[1] & 3) << 8) + buffer[2];
return value; // 0–1023
}
#endif
Before the main loop, initialize SPI:
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) < 0) {
std::cerr << "SPI setup failed.\n";
return 1;
}
Now, the sensor_monitor system collects real data from:
-
DHT11 (temperature + humidity)
-
Soil Moisture sensor via MCP3008
-
LDR (light sensor) via MCP3008
Part 2: AI Crop Health Advisor (ai_advisor)
This part fetches the latest data from the database and analyzes patterns to provide care suggestions.
ai_advisor/main.cpp:
#include <iostream>
#include <vector>
#include <mysql/mysql.h>
#include <ctime>
struct SensorData {
float temp;
float humidity;
int moisture;
int light;
std::string timestamp;
};
// Thresholds for AI advice (can be customized)
const int MOISTURE_THRESHOLD = 400;
const int LIGHT_THRESHOLD = 300;
const float TEMP_HIGH = 35.0;
const float TEMP_LOW = 15.0;
// Function to connect to the database
MYSQL* connectDB() {
MYSQL* conn = mysql_init(NULL);
if (!conn) {
std::cerr << "MySQL init failed\n";
return nullptr;
}
if (!mysql_real_connect(conn, "localhost", "user", "pass", "agriculture", 0, NULL, 0)) {
std::cerr << "DB connection error: " << mysql_error(conn) << "\n";
return nullptr;
}
return conn;
}
// Fetch recent sensor logs
std::vector<SensorData> fetchRecentData(MYSQL* conn, int limit = 10) {
std::vector<SensorData> data;
std::string query = "SELECT temp, humidity, moisture, light, timestamp FROM sensor_logs ORDER BY timestamp DESC LIMIT " + std::to_string(limit);
if (mysql_query(conn, query.c_str()) != 0) {
std::cerr << "Query error: " << mysql_error(conn) << "\n";
return data;
}
MYSQL_RES* res = mysql_store_result(conn);
MYSQL_ROW row;
while ((row = mysql_fetch_row(res))) {
SensorData entry;
entry.temp = std::stof(row[0]);
entry.humidity = std::stof(row[1]);
entry.moisture = std::stoi(row[2]);
entry.light = std::stoi(row[3]);
entry.timestamp = row[4];
data.push_back(entry);
}
mysql_free_result(res);
return data;
}
// Analyze data and recommend actions
void analyzeData(const std::vector<SensorData>& data) {
if (data.empty()) {
std::cout << "No data found.\n";
return;
}
int lowMoistureCount = 0, lowLightCount = 0, tempAlert = 0;
for (const auto& entry : data) {
if (entry.moisture < MOISTURE_THRESHOLD) lowMoistureCount++;
if (entry.light < LIGHT_THRESHOLD) lowLightCount++;
if (entry.temp > TEMP_HIGH || entry.temp < TEMP_LOW) tempAlert++;
}
std::cout << "\n----- AI Crop Health Advisor -----\n";
if (lowMoistureCount >= 3)
std::cout << "Recommendation: Watering the crops is needed (soil appears too dry).\n";
if (lowLightCount >= 3)
std::cout << "Recommendation: Consider providing additional lighting or adjusting shade.\n";
if (tempAlert >= 3)
std::cout << "Recommendation: Temperature conditions are not optimal. Monitor for heating/cooling needs.\n";
if (lowMoistureCount < 3 && lowLightCount < 3 && tempAlert < 3)
std::cout << "All conditions seem good. Crops are healthy!\n";
}
int main() {
MYSQL* conn = connectDB();
if (!conn) return 1;
auto data = fetchRecentData(conn);
analyzeData(data);
mysql_close(conn);
return 0;
}
Conclusion
With this system, we now have:
-
Real-time environmental monitoring of crops using Raspberry Pi GPIO + SPI in C++.
-
An AI-based analyzer suggesting when to water crops, adjust light exposure, or regulate temperature.
This project is a strong foundation for automated smart farming, and it can be extended further by adding actuators (automatic watering, lights) based on AI recommendations!