Daniel Mills
Published © GPL3+

Smart Plant Watering System

Self water plant system created for IoT Bootcamp.

IntermediateWork in progress10 hours142
Smart Plant Watering System

Things used in this project

Hardware components

Grove - Air quality sensor v1.3
Seeed Studio Grove - Air quality sensor v1.3
Grove - Dust Sensor(PPD42NS)
Seeed Studio Grove - Dust Sensor(PPD42NS)
Gravity: Analog Capacitive Soil Moisture Sensor- Corrosion Resistant
DFRobot Gravity: Analog Capacitive Soil Moisture Sensor- Corrosion Resistant
Grove - Relay
Seeed Studio Grove - Relay
Adafruit pump
Gravity: I2C BME680 Environmental Sensor
DFRobot Gravity: I2C BME680 Environmental Sensor
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
Particle Argon

Software apps and online services

adafruit io dashboard

Hand tools and fabrication machines

Laser cutter (generic)
Laser cutter (generic)
3D Printer (generic)
3D Printer (generic)


Read more



You connect air quality sensor, dust sensor, environmental sensor, and moisture sensor to particle argon microcontroller.


Smart Plant Watering

 * Project l14_plantwatering_Final
 * Description: Smart plant watering
 * Author: Daniel Mills
 * Date:03-22-2022

//-----Include and Objects Block
#include "credential.h"                    //creddential for ada fruit dashboard
#include "math.h"
#include <Adafruit_GFX.h>                   //library for graphics
#include <Adafruit_SSD1306.h>               //library for OLED
#include <Adafruit_BME280.h>                //Library for temp
#include <Adafruit_MQTT.h>                  //Library for publishing to Adafruit
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Air_Quality_Sensor.h"            //Library for Air Quality

//Define OLED
#define OLED_RESET D4
Adafruit_SSD1306 display(OLED_RESET);
String DateTime, TimeOnly;  //needed for getting the current time to send to the Adafruit dashboard 

#define BME_ADDRESS 0x76 //BME Address
Adafruit_BME280 bme;
float temp;              //var to store temperature values
float press;             //var to store pressure values
float rHumidity;         //var to store the relative humidity values

//Connecting to Adafruit Webservice
/************ Global State (you don't need to change this!) ***   ***************/ 
TCPClient TheClient; 

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. 

/****************************** Feeds ***************************************/ 
// Setup Feeds to publish or subscribe 
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname> 
Adafruit_MQTT_Publish mqtttemp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temp");
Adafruit_MQTT_Publish mqttpress = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/press");
Adafruit_MQTT_Publish mqttrHumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/rHumidity");
Adafruit_MQTT_Publish mqttmoisture = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/moisture");
Adafruit_MQTT_Publish mqttAQ = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/AirQuality");
Adafruit_MQTT_Publish mqttdust = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/dust");
//Adafruit_MQTT_Publish mqtttime = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/time");  //time object for MQTT
//Adafruit_MQTT_Subscribe mqttSubPumpButton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/pumpButton"); Updated Name
Adafruit_MQTT_Subscribe mqttObj2 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/FeedNamePlantB");  

//Set Sensor Pins
const int PUMP = A4;           //sets the pin to use for the pump
const int DUSTSENSOR = A2;      //sets the pin to use for the dust sensor
const int MOISTURESENSOR = A1;  //pin to use for the moisture sensor
AirQualitySensor sensor(A3);    //pin to use for the AQ sensor

bool status;      //sets for sd card

/************Declare Variables*************/
unsigned long last, lastTime;
int valueB;        //MQTT Button
int moistureValues;  //var to store the moisture probe values
int lastTime2;

//DUST SENSOR Variables (var needed for the dust sensor)
unsigned long duration;             //creates the duration var
unsigned long starttime;
unsigned long sampletime_ms = 5000;//sampe 30s ;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;            //creates var to store the concentration values

//-------------Setup Loop
void setup() {
  Serial.begin(9600);  //Starts the Serial monitor
  //*Setup for OLED
  Time.zone(-7);                              //Sets the mountain time zone
  Particle.syncTime();                        //syncs particle time
  display.begin(SSD1306_SWITCHCAPVCC, 0x3c);  // initialize with the I2C addr 0x3D (for the 128x64)
  display.display();                          //show splashscreen (To make sure that the OLED is working)

  //*Setup for Dust Sensor
  pinMode(DUSTSENSOR,INPUT);       //sets the pinMode for the dust sensor
  pinMode(MOISTURESENSOR, INPUT);  //sets the pinMode for the moisture probe
  pinMode(PUMP, OUTPUT);           //sets the pinMode the the motor pump

  //Connect to WiFi without going to Particle Cloud
  WiFi.connect();               //connect to wifi
  while(WiFi.connecting()) {    //for connecting to another broker

  mqtt.subscribe(&mqttObj2);  //subscribe to pump button from Adafruit  --changed
  starttime = millis();  //stores current time to the starttime var

//--------Start of Main Loop
void loop() { 
  //*Loop for OLED
  DateTime = Time.timeStr();              // Current Date and Time from Particle Time class
  TimeOnly = DateTime.substring(11 ,19) ; // Extract the Time from the DateTime String

  //=====Main Functions=======
  //*MQTT Start
  // Ping MQTT Broker every 2 minutes to keep connection alive
  if ((millis()-last)>120000) {               //function to ping the MQTT broker
      Serial.printf("Pinging MQTT \n");             
      if(! mqtt.ping()) {
        Serial.printf("Disconnecting \n");
    last = millis();

  //*MQTT Subscription
  Adafruit_MQTT_Subscribe *subscription;                                             //looks for MQTT subscriptions for button input to turn on motor pump
  while ((subscription = mqtt.readSubscription(100))) {                              //looks for receiving signal
     if (subscription == &mqttObj2) {
        valueB = atoi((char *)mqttObj2.lastread);                                    //takes last data and converts it char and converts it to a float
        Serial.printf("Received %i from Adafruit.io feed FeedNameB \n",valueB);   //prints to screen

  if (valueB == 1){  //if the the soil is dry(less than value), pump water
    digitalWrite(PUMP, HIGH);                 //turns pump on
    Serial.printf("Pump is ON \n");
    digitalWrite(PUMP, LOW);                  //turns pump off
    Serial.printf("Pump is OFF \n");
  if ((millis()-lastTime2)>(60000*30)) {   //
    if (moistureValues > 2300 ){  //if the the soil is dry(less than value), pump water
      digitalWrite(PUMP, HIGH);                 //turns pump on
      Serial.printf("Pump is ON \n");
      digitalWrite(PUMP, LOW);                  //turns pump off
      Serial.printf("Pump is OFF \n");
    lastTime2 = millis();
    duration = pulseIn(DUSTSENSOR, LOW);
    lowpulseoccupancy = lowpulseoccupancy+duration;
    if ((millis()-starttime) > sampletime_ms)//if the sampel time == 30s
      ratio = lowpulseoccupancy/(sampletime_ms*10.0);  // Integer percentage 0=>100
      concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
      lowpulseoccupancy = 0;
      starttime = millis();
  showDisplayValues(); //function to print sensor values to OLED
  //*Reads and Publishes Values to Adafruit 
  if((millis()-lastTime > 20000)) {
    //*Air Quality Check Function
    int quality = sensor.slope();
    Serial.print("Sensor value: ");
    //Checks how fresh the air is
    if (quality == AirQualitySensor::FORCE_SIGNAL) {
      Serial.println("High pollution! Force signal active.");
    else if (quality == AirQualitySensor::HIGH_POLLUTION) {
      Serial.println("High pollution!");
    else if (quality == AirQualitySensor::LOW_POLLUTION) {
      Serial.println("Low pollution!");
    else if (quality == AirQualitySensor::FRESH_AIR) {
      Serial.println("Fresh air.");

    moistureValues = analogRead(MOISTURESENSOR);         //gets the values from the moisture sensor

    temp = (bme.readTemperature()*1.8)+32;  //gets the temp values  and converts them to F
    press = bme.readPressure()*0.00030;     //converts the press values to inches of murcury
    rHumidity = bme.readHumidity();         //gets RH values from the BME sensor

    if(mqtt.Update()) {  //starts MQTT updats
      mqtttemp.publish(temp);                                      //publishes the temp values  Adafruit
      Serial.printf("Publishing Temp %0.2f \n", temp);             //prints temp values to serial monitor
      mqttpress.publish(press);                                    //pub the pressure values
      Serial.printf("Publishing Pressure %0.2f \n", press);        //prints pressure to serial monitor
      mqttrHumidity.publish(rHumidity);                            //publishes rHumidity values
      Serial.printf("Publishing RH %0.2f \n", rHumidity);          //prints the RH values
      mqttmoisture.publish(moistureValues);                        //publishes the moisture values
      Serial.printf("Publishing Moisture %i \n", moistureValues);  //prints the moisture values
      mqttAQ.publish(sensor.getValue());                           //gets the Air Quality values
      Serial.printf("Publishing AQ %i \n", sensor.getValue());     //publishes the AQ Values
      mqttdust.publish(concentration);                             //gets the Dust
      Serial.printf("Publishing Dust Values %0.2f \n", concentration);
      mqttdust.publish(DateTime.c_str());                             //gets the Dust
      //Serial.printf(" Date and time is %s\n", DateTime.c_str());
   lastTime = millis();


//-----------------Void Functions
// Function to connect and reconnect as necessary to the MQTT server.
void MQTT_connect() {  //this function is important to include for connecting to MQTT
  int8_t ret;
  // Stop if already connected.
  if (mqtt.connected()) {
  Serial.print("Connecting to MQTT... ");
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
      Serial.printf("%s\n",(char *)mqtt.connectErrorString(ret));
      Serial.printf("Retrying MQTT connection in 5 seconds..\n");
      delay(5000);  // wait 5 seconds
  Serial.printf("MQTT Connected!\n");   //output for if connection was successful

//*Prints values to the OLED
void showDisplayValues(){
  display.clearDisplay();                             //clears the previous values
  display.printf("Temp: %0.1f\n", temp);              //shows the temp values
  display.printf("Pressure: %0.1f\n", press);         //shows the pressure values
  display.printf("Humidity:  %0.1f\n", rHumidity);    //shows the rel humidity values
  display.printf("AQ: %i \n", sensor.getValue());     //gets the air quality
  display.printf("Moisture: %i \n", moistureValues);  //gets the moisture values
  display.printf("Dust: %0.2f \n", concentration);    //gets the dust values
  display.printf("Time is %s\n", TimeOnly.c_str());   //gets time


Daniel Mills

Daniel Mills

3 projects • 7 followers
Thanks to rawpixel.com, Suzuki.


Add projectSign up / Login