Project in progress
eCO-SENSE: Soil Sensors Powered by Plant Photosynthesis

eCO-SENSE: Soil Sensors Powered by Plant Photosynthesis

We aim to provide a low-cost precision agriculture solution powered by biophotovoltaics, and we start with developing a prototype.

  • 6 respects

Components and supplies

Necessary tools and machines

3D Printer (generic)
09507 01
Soldering iron (generic)

Apps and online services

Ide web
Arduino IDE
Adafruit Bluefruit LE Connect Version 3.4.1

About this project


Using a unique power source, where we are able to draw power from the growth of the plants themselves, we aim to provide a low-cost sensor infrastructure to empower farmers with precision agriculture technology.

The goals of this project are to:

1) Identify key soil parameters to be measured: this can inform farmers on further actions they can take to help improve soil health and yields.

2) Develop a low-cost, low-powered soil sensing architecture: current precision agriculture solutions are expensive and out-of-reach to many farmers in the developing world.

3) Enable remote transmission of data.

4) Develop the sensing kit such that it can be deployed remotely: This requires a sturdy outer casing that shields the system from the elements.

5) Develop a way to store and display the data: the end-goal would be to provide recommended actions that a farmer can take based on the sensor measurements.

Biophotovoltaic Cell

We are working together with Dr Paolo Bombelli from the University of Cambridge to use the novel technology that he's developing so that we can eventually power our sensors in-situ via the growth of the plants themselves.

Linking up the biophotovoltaic cell with our sensors remains as work-in-progress, and currently we are still sticking with powering our sensors via traditional battery cells.

Key Soil Parameters to Be Measured

Eventually we could be able to measure many more parameters, but, as a start, we wanted to focus on a few key parameters.

We decided to focus on trying to maximise microbial activity in soil. The level of microbial activity can be a strong indicator of the soil health, which then directly impacts yields.

The soil parameters we decided to measure are:

  • Temperature
  • Moisture
  • Gas

The amount of gas flux from the soil can be a proxy for the level of microbial activity in the soil. There is an optimum soil moisture amount for maximising microbial activity in the soil, and this is based on a paper by Skopp et al. (1990). In addition, temperature can also have an effect on microbial activity too: in general, the higher the temperature, the greater the microbial activity, and vice versa.

Assembling the Sensors Together

We started off with an Arduino Uno board, together with a breadboard to connect all the sensors to it.


For temperature, we decided to use the DHT-22 sensor.

The connections used for this project were:

GND --> to the Arduino GND

VOL --> to the Arduino 5V

DAT --> to the Arduino Digital '7'

(An additional output from the DHT-22 sensor is humidity)


For soil moisture, we used the FC-28 Soil Moisture probe.

The connections used for this project were:

GND --> to the Arduino GND

VOL --> to the Arduino 5V

A0 --> to the Arduino Analog 'A2'

Note that calibration is needed for this sensor: we measured the output values in moisture-saturated (100%) soil as well as dry soil (0%), and put these values in the Arduino Sketch (refer to attached example Arduino Sketch code). The final output will then be soil moisture given as a percentage from 0 to 100%.


For gas flux measurements, we used the SGP30 gas sensor.

The circuit connections used are:

GND --> to the Arduino GND

VIN --> to the Arduino 5V

SCL --> to the Arduino Uno Analog 'A5'

SDA --> to the Arduino Uno Analog 'A4'

Note that we soldered pins into the holes of the sensor and then connected the sensor on the breadboard.

This gas sensor outputs a Total Volatile Organic Compound (TVOC) reading and an equivalent carbon dioxide reading (eCO2). We have decided to use just the eCO2 output.

Remote Transmission of Data - via Bluetooth

Eventually, we wish to utilise LoRoWAN for wireless transmission of data. However, for a proof-of-concept, we utilise Bluetooth transmission capabilities instead. We use the nRF8001 Bluefruit LE Breakout component for this.

The circuit connections used are:

VIN --> to the Arduino 5V pin

GND --> to the Arduino GND

SCK --> to SPI clock (Digital 13)

MISO --> to SPI MISO (Digital 12)

MOSI --> to SPI MOSI (Digital 11)

REQ --> to SPI Chip Select Pin (Digital 10)

RST --> connects to Digital 9

RDY --> this is the interrupt out from the nRF8001; connect to Digital 2

Note that pins were also soldered onto the chip to enable easy connection with the breadboard.

One of the advantages of this bluetooth module over others is the ease of displaying the sensor data via a mobile app.

See below for a full circuit schematic with all the connections.

Making a Protective Casing with 3D Printing

To enable deployment in the fields for long periods of time, we designed a protective casing for the whole sensor unit.

One of the considerations when building the casing was to be able to shield most of the circuiting while providing outlets for the soil moisture probe as well as for the power source connection. In particular, we designed it such that the soil moisture probe could reach up to 15cm in depth. The other sensors remained above soil.

One other consideration for accurate gas sensor usage was allowing the gas to escape instead of building up within the casing. To do so, we inserted some ventilation holes on the sides. (The idea being that if it rained, then water would at least not seep in through the top if the holes were on the sides)

Displaying Data

Eventually, we wish to be able to provide full data interpretation services, where we can give recommended actions based on the sensor measurements.

For a first proof-of-concept, we output the raw data.

We utilise the Adafruit bluetooth app.

Mobile app (Android/iOS): see

Desktop app: see

We output Temperature (degrees Celsius), eCO2 (parts per million, ppm) and Moisture (in percentage of soil moisture). An additional field we output is ambient humidity (in percentage). We are able to capture real-time data and we can adjust the time interval for receiving data as well.

Using the data to provide actions to optimise soil health - Soil Moisture as an example

As mentioned earlier, Skopp et al. (1990) suggested that there exists an optimum soil moisture content for microbial activity, which can be proxied by the amount of gas flux from the soil. However, the general relationship in dependent on many factors, such as soil type as well as weather parameters.

An updated model suggested by Yan et al. (2018) includes parameterisations which allow us to account for soil type variations. Using this model, we are then able to obtain a theoretical relationship between moisture content and microbial respiration rate for various soil types.

As a first step, using this model, we are able to use the soil moisture sensor's data output to determine how far the soil moisture is away from the optimum content. If the moisture content is lower than optimal, this would be a signal to add more water to the soil, and vice versa.

The next steps would be to:

- Conduct field studies to measure the actual relationship between gas flux (using the gas sensor's data output) and soil moisture content for different types of soil and weather conditions, to refine the theoretical model to suit our purposes

- Expand the model to include an irrigation parameterisation, so that we can recommend how much more/less water to add to reach the optimal level

- Expand the model to include other factors relevant to soil health (e.g. fertiliser content)

Power considerations

In the long-term, we intended to power the hardware platform by means of a biophotovoltaic cell (BPV), a novel technology than can generate currents (i.e. electricity) through the growth of the plants themselves. In the first step, we considered the power consumption of our device versus the power generation of a commercial BPV. We measured the power consumption of our low-power device to be approximately 300 mW. A commercial BPV can supply 2 mW of power. In consequence, an intermediate charge-storage is necessary. We choose a supercapacitor due the robustness and long life-time. A proof-of-concept experiement demonstrated that we can charge-up a supercapacitor (1 F, 7.5 Vmax) with a potentiostat (as a model for the BPV) to 7.5 V, and then release the charges until the voltage drops to 3.3 V, the lowest operating voltage of the Arduino hardware. The device ran for 1 min 30s on power supplied solely by the supercapacitor - a sufficient time for starting-up, measuring the data, averaging and transmission to our backend network. The next steps include building a custom PCB that automates the switching between charging and discharging cycles. We then aim to integrate an acutal BPV for charging up the supercapacitor.

Future Plans

Here are some of the things that's still work-in-progress in the near-future:

  • Linking up the biophotovoltaic cell with our sensing kit
  • Further programming the backend side for our data storage/processing
  • Integrate fertiliser sensiers and refining our model (e.g. not only optimizing for moisture but also for fertiliser)
  • Developing a nice user interface (via an app/website) for an end user

We then eventually hope to do some pilot testing in the UK, in particular to get some real-world data on different crop/soil types in order to build our recommendations engine.


Skopp, J., Jawson, M. D., Doran, J. W. (1990). Steady-state aerobic microbial activity as a function of soil water content. Soil Sci. Soc. Am. J., 54:1619-1625. doi: 10.2136/sssaj1990.03615995005400060018x

Yan, Z. et al. (2018). A moisture function of soil heterotrophic respiration that incorporates microscale processes, Nat. Comm., 9:2562. doi: 10.1038/s41467-018-04971-6


eCO-SENSE Example Arduino Sketch Arduino
This is an example for our nRF8001 Bluetooth Low Energy Breakout

  Pick one up today in the adafruit shop!

Adafruit invests time and resources providing this open source code, 
please support Adafruit and open-source hardware by purchasing 
products from Adafruit!

Written by Kevin Townsend/KTOWN  for Adafruit Industries.
MIT license, check LICENSE for more information
All text above, and the splash screen below must be included in any redistribution

// This version uses the internal data queing so you can treat it like Serial (kinda)!

#include <SPI.h>
#include "Adafruit_BLE_UART.h"
#include <math.h>
#include <Wire.h>
#include "Adafruit_SGP30.h"
#include <DHT.h>;

// Connect CLK/MISO/MOSI to hardware SPI
// e.g. On UNO & compatible: CLK = 13, MISO = 12, MOSI = 11
#define ADAFRUITBLE_RDY 2     // This should be an interrupt pin, on Uno thats #2 or #3


/*     ---------------------------------------------------------
 *     |  Arduino Experimentation Kit Example Code             |
 *     |  CIRC-10 .: Temperature :. (TMP36 Temperature Sensor) |
 *     ---------------------------------------------------------
 *  A simple program to output the current temperature to the IDE's debug window 
 *  For more details on this circuit: 
Adafruit_SGP30 sgp;

// Moisture Variables
int sensor_pin = A2;
int moisture;

// DHT22 Constants
#define DHTPIN 7     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino

//DHT 22 Variables
int chk;
float hum;  //Stores humidity value
float temp; //Stores temperature value

 * setup() - this function runs once when you turn your Arduino on
 * We initialize the serial connection with the computer

 * getVoltage() - returns the voltage on the analog input defined by
 * pin
    Configure the Arduino and start advertising with the radio
void setup(void)
  while(!Serial); // Leonardo/Micro should wait for serial init
  Serial.println(F("Adafruit Bluefruit Low Energy nRF8001 Print echo demo"));


  Serial.println("SGP30 test");

  if (! sgp.begin()){
    Serial.println("Sensor not found :(");
    while (1);
  Serial.print("Found SGP30 serial #");
  Serial.print(sgp.serialnumber[0], HEX);
  Serial.print(sgp.serialnumber[1], HEX);
  Serial.println(sgp.serialnumber[2], HEX);

  // If you have a baseline measurement from before you can assign it to start, to 'self-calibrate'
  //sgp.setIAQBaseline(0x8E68, 0x8F41);  // Will vary for each sensor!

    Constantly checks for new events on the nRF8001
aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;

int counter = 0;
void loop()
  // temperature and humidity stuff from DHT22

  //Read data and store it to variables hum and temp
  hum = dht.readHumidity();
  temp= dht.readTemperature();
  //Print temp and humidity values to serial monitor
  Serial.print("Humidity: ");
  Serial.print(" %, Temp: ");
  Serial.println(" Celsius");

  //moisture stuff from the moisture sensor
  moisture = analogRead(2);

  //moisture measurements must be calibrated: in this case, we measured 1030 for dry, and 400 for wet soil, and the output will be a percentage
  moisture = map(moisture,1030,400,0,100);

  //gas measurements from the sgp30 gas sensor
  if (! sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
  Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
  Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");

  if (! sgp.IAQmeasureRaw()) {
    Serial.println("Raw Measurement failed");
  Serial.print("Raw H2 "); Serial.print(sgp.rawH2); Serial.print(" \t");
  Serial.print("Raw Ethanol "); Serial.print(sgp.rawEthanol); Serial.println("");

  if (counter == 30) {
    counter = 0;

    uint16_t TVOC_base, eCO2_base;
    if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
      Serial.println("Failed to get baseline readings");
    Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX);
    Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX);
  // Tell the nRF8001 to do whatever it should be working on.

  // Ask what is our current status
  aci_evt_opcode_t status = BTLEserial.getState();
  // If the status changed....
  if (status != laststatus) {
    // print it out!
    if (status == ACI_EVT_DEVICE_STARTED) {
        Serial.println(F("* Advertising started"));
    if (status == ACI_EVT_CONNECTED) {
        Serial.println(F("* Connected!"));
    if (status == ACI_EVT_DISCONNECTED) {
        Serial.println(F("* Disconnected or advertising timed out"));
    // OK set the last status change to this one
    laststatus = status;

  if (status == ACI_EVT_CONNECTED) {
    // Lets see if there's any data for us!
    if (BTLEserial.available()) {
      Serial.print("* "); Serial.print(BTLEserial.available()); Serial.println(F(" bytes available from BTLE"));
    // OK while we still have something to read, get a character and print it out
    while (BTLEserial.available()) {
      char c =;

    // Next up, see if we have any data to get from the Serial console

//    if (Serial.available()) {
      // Read a line from Serial
      String s = String( String(temp) + "," + String(sgp.eCO2) + "," + String(moisture) + "," + String(hum) + "\n");
      // We need to convert the line to bytes, no more than 20 at this time
      uint8_t sendbuffer[20];
      s.getBytes(sendbuffer, 20);
      char sendbuffersize = min(20, s.length());

      Serial.print(F("\n* Sending -> \"")); Serial.print((char *)sendbuffer); Serial.println("\"");

      // write the data
      BTLEserial.write(sendbuffer, sendbuffersize);


//    }


eCOSENSE schematic
Presentation1 remn5fhbos


Similar projects you might like

Double Plant Watering

Project in progress by adamneareva and Fabio Cardoso

  • 12 respects

Arduino101 / tinyTILE BLE: Match-Making Sunglasses

Project tutorial by Kitty Yeung

  • 45 respects

DIY Plant Moisture Sensor

Project tutorial by millerman4487

  • 35 respects

The Quantified Cactus: An Easy Plant Soil Moisture Sensor

Project tutorial by Jen Looper

  • 29 respects

Arduino Powered CPR Feedback Device

Project showcase by David Escobar

  • 30 respects

Automated Watering Plant

Project in progress by Saikan45

  • 41 respects
Add projectSign up / Login