Published © LGPL

CNM Ingenuity IoT Plant Watering System

Creates a functioning automatic and manual plant watering system featuring Particle Argon, 5V power supply and sensors to activate the pump.

BeginnerShowcase (no instructions)Over 2 days467
CNM Ingenuity IoT Plant Watering System

Things used in this project

Hardware components

Particle Argon
BME/BMP 280 Digital 5V Temperature Humidity Sensor Atmospheric Barometric Pressure Board IIC I2C Breakout for Arduino
Analog Capacitive Soil Moisture Sensor V1.2 Corrosion Resistant With Cable Wire
OLED: 1.3 Inch 4Pin White OLED LCD Display 12864 IIC I2C Interface Module Geekcreit for Arduino - products that work with official Arduino boards
RELAY SWITCH: KNACRO SRD-12VDC-SL-C 12V Delay Relay Module Delay Switch with Signal optocoupler. Adjustable Trigger time Repeat Trigger
MOTORIZED WATER PUMP: Machifit JT80SL DC 3-6V Water Pump 120L/H Ultra-quiet Micro Horizontal Submersible Mini Water Pump
Grove - Dust Sensor(PPD42NS)
Seeed Studio Grove - Dust Sensor(PPD42NS)
PUMP VINYL TUBING:EZ-FLO 1/4-in ID x 10-ft PVC Clear Vinyl Tubing Item #879260

Software apps and online services

Windows 10
Microsoft Windows 10


Read more

Custom parts and enclosures

3-D Flower Pot

4 1/4" dia. flower pot containing soil and plant (Japanese decorative grass). Pot made from PLA composite in an Ultimaker III 3D printer using Cura 4.6 printing software


L14_04_PlantWater Fritzing Diagram

Circuitry illustration for Plant Watering system including these components: Particle Argon, I2C OLED display, Soil Moisture Probe, BME280 sensor, relay switch, pump motor, Grove PPD42NS dust sensor


C++ Plant Watering System driver program

Program created in Visual Studio v 1.47.3
 * Project L14_04_PlantWater
 * Description: 
 * This program uses the Capacitive Soil Moisture probe to take moisture readings from the
 * BME280 sensor humidity readings. Use an analog read to obtain moisture readings from the sensor.
 * Record to my lab notebook note the moisture readings for these condions:
 * 1) Empty Cup
 * 2) Submerged in water to the notch
 * 3) Dry Soil
 * 4) Soil after plant is watered
 * In the prgram, display each moisture reading to the OLED with a Time-stamp:
 * Time. Also, integrate a button to manually water the plant.    
 * 99:99:99 
 * Moisture
 * 99.99
 * Author: Ted Fites
 * Date: 8/11/20
// HEADER section ********************************************************
// include lines 11-13 & 18 below from Adafruit library header file (lines 19-23). Need to only install
// Adafruit_SSD1306 header file for each program referencing it (it already includes Adafruit_GFX.h).
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_BME280.h"

// Use line #26-30 for subsequent programs just as is:
#include <Adafruit_MQTT.h>

#include "Adafruit_MQTT/Adafruit_MQTT.h" 
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h" 
#include "Adafruit_MQTT/Adafruit_MQTT.h" 

/************************* Adafruit.io Setup *********************************/ 
#define AIO_SERVER      "io.adafruit.com" 
#define AIO_SERVERPORT  1883                   // use 8883 for SSL 
#define AIO_USERNAME  "Ted_Fites"
#define OLED_RESET D4

Adafruit_SSD1306 display(OLED_RESET); // Declare object from lib class supplying OLED 128x64 pixel display access
// Define bme as the I2C interface to the BME280 sensor

Adafruit_BME280 bme; // Declare object for BME sensor

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_Subscribe subMoistureBtn = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/L14_04_PlantBtnFeed"); 
Adafruit_MQTT_Publish pubMoisture = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/L14_04_Moisture");
Adafruit_MQTT_Publish pubHumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/L14_04_Humidity");
Adafruit_MQTT_Publish pubTemp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/L14_04_Temperature");
Adafruit_MQTT_Publish pubDust = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/L14_04_Dust");

// Constants & variables
bool status;
char currentDateTime[25];
char currTime[9];
const int pinA5=A5;
const int PIN_VBUS_5V=D7; //Provides 5V power input to relay switch (and pump motor) from Argon pin D7
const int moistureThreshold=1770; // Water pump threshold set by L14_02_SoilMoisture program
float humBME;
float tempBME;
int moistureVal=0;
int btnMoistureVal;
String dateTime;
String timeOnly;
unsigned long int last;
// FM07: Dust sensor variables
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 2000; 
unsigned long lowpulseoccupancy = 0;
float ratio = 0.0;
float concentration = 0.0;
// FM07: END Dust sensor variables

// end HEADER section *******************************************************************************************
//SYSTEM_MODE(SEMI_AUTOMATIC); // Allows project flashing while Argon is disconnected from any wifi internet
void setup() 
// 1) Adafruit OLED: include lines 24-25 below from Adafruit library header file (lines 62-63)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  // init done

  display.display(); // show Adafruit splashscreen to OLED
  delay(2000);  // maintain display for 2 seconds
/* Connect the Particle Argon to the Particle Cloud to synchronize its
* clock to the current local time.
  Serial.printf("Lesson 14_04_PlantWater\n");
  Time.zone(-6); // Set Time Zone to MDT (UTC -7)
//  unsigned long int cur= millis ();
  // Request time synch from Particle Cloud
  waitUntil (Particle.syncTimeDone);
  pinMode(pinA5,INPUT); // Declare the Capacitive 
  * 2) BME 280sensor : Use method .begin for bme object to turn on sensor 
    while(!Serial);    // time to get serial running
    delay (1000);
    Serial.println(F("BME280 test"));   // "F" in println statement: Reference to FLASH memory on SD card)
    status = bme.begin(0x76);  
    if (!status) {
        Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
        Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),HEX);
        Serial.println("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085");
        Serial.println("   ID of 0x56-0x58 represents a BMP 280,");
        Serial.println("        ID of 0x60 represents a BME 280.");
        Serial.println("        ID of 0x61 represents a BME 680.");
        while (1);
    else {
      Serial.println("BME280 Up and Running");
  // Setup MQTT subscription for onoff feed.
  // READ data from the dashboard "L14_04_PlantWater" button to light up Argon LED D7
  pinMode(PIN_VBUS_5V,OUTPUT); // Argon on-board LED to light up when pressing DB button 

  pinMode(DUST_SENSOR_INPIN,INPUT); // Declare dust sensor pin
  starttime = millis(); // Set dust sensor base sample start time 


void loop() 
//*************************************  MAIN LOOP  **********************************
  M01_MQTT_connect(); //FM01
// Keep connection alive between publishings
 // Stop if already connected.
  Serial.print("Connecting to MQTT... ");
  if ((millis()-last)>120000) {
      Serial.printf("Pinging MQTT \n");
      if(! mqtt.ping()) {
        Serial.printf("Disconnecting \n");
      last = millis();
  M02_Subscribe_Moisture_Button(); // FM02-Set up button on L14_04_WaterPlant DB to manually activate pump
  M03_get_Curr_Time(); //FM03
  M04_get_Moisture_BME_data(); //FM04
  M05_display_Screen_Info();  //FM05
  M07_Activate_Dust_Sensor(); //FM07
  M08_Publish_Values(); //FM08
  if (moistureVal>=moistureThreshold)
  * AUTOMATIC (PROGRAMMED) CHECK TO ACTIVATE PUMP:If the moisture level (dryness) exceeds 
  * the threshold level, then activate the pump
  * to add water to the pot. Otherwise write LOW to pin D7 to deactivate the pump. 
    Serial.printf("***PUMP ACTIVATED***\n");  
    delay(500);  // Activate the pump for 1/2 sec (per BR, isolated delay() OK to use)
} // end MAIN loop  ********************************************************************

/* FM01: MQTT_connect()
 *Function to connect and reconnect as necessary to the MQTT server.
 *Should be called in the loop function and it will take care if connecting.
void M01_MQTT_connect() 
  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.println("Retrying MQTT connection in 5 seconds...");
       delay(5000);  // wait 5 seconds
  Serial.println("MQTT Connected!");

void M02_Subscribe_Moisture_Button()
// FM02: Subscribe_Moisture_Button
  // this is our 'wait for incoming subscription packets' busy subloop
  // try to spend your time here
 // read (subscribe) the data from the dashboard button every 2 seconds
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(2000))) 
    if (subscription == &subMoistureBtn) 
//      moistureVal = atof((char *)subMoistureBtn.lastread);
      btnMoistureVal = atoi((char *)subMoistureBtn.lastread);
      Serial.printf("BTNmoistureVal > %i\n",btnMoistureVal);
} // end SubscribeMoistureButton

void M03_get_Curr_Time()
// FM03: get_Curr_Time()
} // end get_Curr_Time()

void M04_get_Moisture_BME_data()
// FM04: get_Moisture_BME_data()
  Serial.printf("get_Moisture_BME_data MOISTURE > %i\n",moistureVal);
  tempBME = (bme.readTemperature() * 9.0 / 5.0) + 32.0;
  humBME = bme.readHumidity();
} // end get_Moisture_BME_data

void M05_display_Screen_Info()
//FM05: display_Screen_Info()
  Serial.printf("Current time & Moisture> %s %i \n",currTime, moistureVal);

  display.clearDisplay();   // clears the screen and buffer
  display.setTextSize(1);  // Double from 1:1 size for improved readability
  display.setTextColor(WHITE); // Draw white text
  display.printf("Time: ");
//  display.setTextColor(WHITE); // Draw white text
  display.printf("Moisture:    ");
  display.printf("Humidity:    ");
  display.printf("Temperature: ");
  delay(5000); // re-display data to the OLED every 5 seconds
} //end display_Screen_Info()

void M07_Activate_Dust_Sensor()
// FM07: Activate_Dust_Sensor()
  duration = pulseIn(DUST_SENSOR_INPIN, LOW);
  lowpulseoccupancy = lowpulseoccupancy+duration;
  if ((millis()-starttime) >= sampletime_ms) //if the time exceeds 30ms, take a sample
    ratio = lowpulseoccupancy/(sampletime_ms*10.0);  
    concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; 
    Serial.printf("DUST SENSOR Concentration > %0.2f  pcs/0.01cf \n",concentration);
    pubDust.publish(concentration); // publish the DUST 
    Serial.printf("Publishing Dust (pcs/0.01cf) %0.2f \n",concentration); 

    lowpulseoccupancy = 0;
    starttime = millis();
} // END Activate_Dust_Sensor()

void M08_Publish_Values()
//FM08: Publish_Values()
  if((millis()-last > 10000)) // 10 secs
    if(mqtt.Update()) {
      pubMoisture.publish(moistureVal); // publish the MOISTURE
      Serial.printf("Publishing Moisture %i \n",moistureVal); 
      pubHumidity.publish(humBME); // publish the HUMIDITY
      Serial.printf("Publishing Humidity %5.2f \n",humBME); 
      pubTemp.publish(tempBME); // publish the TEMPERATURE
      Serial.printf("Publishing Temp %5.2f \n",tempBME); 
    last = millis();
} // end Publish_Values()




4 projects • 3 followers


Add projectSign up / Login