Carli Stringfellow
Published

Rain Simulated Self Watering Planter

This planter can water your plants with droplets that sit on the leaves and shower the total soil area!

BeginnerShowcase (no instructions)12 hours153
Rain Simulated Self Watering Planter

Things used in this project

Hardware components

Argon
Particle Argon
×1
General Purpose Transistor PNP
General Purpose Transistor PNP
×1
Resistor 2.21k ohm
Resistor 2.21k ohm
×1
Resistor 220 ohm
Resistor 220 ohm
×1
Gravity: Analog Capacitive Soil Moisture Sensor- Corrosion Resistant
DFRobot Gravity: Analog Capacitive Soil Moisture Sensor- Corrosion Resistant
×1
DC motor (generic)
×1
Grove - Air quality sensor v1.3
Seeed Studio Grove - Air quality sensor v1.3
×1
Grove - Dust Sensor(PPD42NS)
Seeed Studio Grove - Dust Sensor(PPD42NS)
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Gravity: I2C BME280 Environmental Sensor
DFRobot Gravity: I2C BME280 Environmental Sensor
×1

Software apps and online services

Visual Studio 2017
Microsoft Visual Studio 2017
Fusion 360
Autodesk Fusion 360

Hand tools and fabrication machines

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

Story

Read more

Custom parts and enclosures

showertop_v2_PGmlgMRRvk.stl

Shower Head for Rain Simulation

Schematics

plant_water_fritz_IlqkuKZa70.png

plant_water_schematic_Rk3Nkk3P68.png

Code

L14_04_PlantWater.ino

C/C++
/*
 * Project L14_04_PlantWater
 * Description: Self watering planter
 * Author: Carli Stringfellow
 * Date: 04-20-2021
 */

#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT.h" 
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h" 
#include "Adafruit_MQTT/Adafruit_MQTT.h" 
#include "Air_Quality_Sensor.h"
#include "Adafruit_BME280.h"
#include "credentials.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"
#include "Math.h" 

/************ Global State (you don't need to change this!) ***   ***************/ 
// SYSTEM_MODE(SEMI_AUTOMATIC); //You need to comment out to get real time
TCPClient TheClient; 

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. 
Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY); 

/****************************** Feeds ***************************************/ 
// Setup Feeds to publish or subscribe 
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname> 
Adafruit_MQTT_Subscribe waterButtonFeed = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/manualwater");
Adafruit_MQTT_Publish moistureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/soilmoisturelevel");
Adafruit_MQTT_Publish temperatureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/roomtemperature");
Adafruit_MQTT_Publish humidityFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/roomhumidity");
Adafruit_MQTT_Publish dustParticleFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/dustconcentration");
Adafruit_MQTT_Publish airQualityFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/indoorairquality");

// MQTT publish and subscribe to adafruit cloud (declarations)
unsigned long last;
unsigned long lastTime;
bool waterValue;

//Air pollution sensor (declarations)
AirQualitySensor airSensor(A0);
unsigned long lastTimeAir;

//Dust sensor (declarations)
const int DUSTPIN = A5;
unsigned long duration;
unsigned long startTime;
unsigned long sampleTime_ms = 2000;
unsigned long lowPulseOccupancy = 0;
float ratio = 0;
int concentration = 0;


//Capacitive soil moisture sensor v1.2 (declarations)
int soilMoisture;
const int SOILPIN = A4;

//Water pump (declarations)
const int WATERPIN = A2;
int pumpTimer;

//OLED (declarations)
const int OLED_RESET = D4; 
Adafruit_SSD1306 display(OLED_RESET);
int rot = 2;

//Timestamp (declarations)
String DateTime;
String TimeOnly;
char currentDateTime[25], currentTime[9];

//BME (declarations)
const int chipSelect = 4;
float tempF;
float humidity;
Adafruit_BME280 bme;

void setup() {
  Serial.begin(9600);
  bme.begin(0x76); // Turns on bme sensor 
  while (!Serial);
  delay(100);

  pinMode(WATERPIN, OUTPUT);
  pinMode(SOILPIN,INPUT);
  pinMode(DUSTPIN,INPUT);
  pinMode(A0, INPUT);
  startTime = millis(); //Checks current time

    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  display.display ();
  delay(1000);
  display.clearDisplay();  
  display.setRotation(rot);

  //Sets the timezone to mountain daylight time
  Time.zone(-6);
  Particle.syncTime();

  Serial.printf("Connecting to Internet \n");
  WiFi.connect();
  while(WiFi.connecting()) {
    Serial.printf(".");
    delay(100);
  }
  Serial.printf("\n Connected!!!!!! \n");
  // Setup MQTT subscription for onoff feed.
  mqtt.subscribe(& waterButtonFeed);

    if (airSensor.init()) {
      Serial.println("Air Sensor ready.");
    }
    else {
      Serial.println("Air Sensor ERROR!");
    }
} 
//THE VOIIIIIID LOOOOOOOP
void loop() {  
  MQTT_connect(); //Connects to wifi
  timeAndDisplay(); // Displays BME data and time
  dustSensor(); //Detects dust particles
  airQualityCheck(); //Checks air quality
  cloudData(); //Pings internet and publishes/subscribes to adafruit cloud
   
}

// 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 MQTT_connect() {
  int8_t ret;
 
  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }
 
  Serial.print("Connecting to MQTT... ");
 
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println("Retrying MQTT connection in 5 seconds...");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
  }
  Serial.println("MQTT Connected!");
}
//Calls for current time and displays time and other readings:
void timeAndDisplay() {

  DateTime = Time.timeStr();
  TimeOnly = DateTime.substring(11,19);

  // Converts String to char arrays 
  DateTime.toCharArray(currentDateTime, 25);
  TimeOnly.toCharArray(currentTime,9);
  display.display();
  delay(2000);
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(WHITE);        // Draw WHITE text
  display.setCursor(0,0);             // Start at top-left corner

// CAN BE SEEN ON OLED SCREEN
    tempF = 1.8*(bme.readTemperature())+32; // Converts celsius to fahrenheit
    display.printf("Tempurature:   %0.1f\n", tempF);
  //  Serial.printf("Tempurature is %0.1f\n" ,tempF);

    humidity = bme.readHumidity(); // Displays humidity
    display.printf("Humidity:      %0.1f\n", humidity);
  //  Serial.printf("Humidity is %0.1f\n" ,humidRH);

    display.printf("Dust Parts:    %i\n", concentration);  
    // Serial.printf("Dust Particles: %i\n", concentration);
    soilMoisture = analogRead(SOILPIN);
    Serial.printf("Soil Moisture %i \n", soilMoisture);
    display.printf("Soil Moisture: %i\n", soilMoisture); // Displays soil moisture
    display.printf("%s\n", currentTime);  // Displays current MDT
    display.display();
}

//SUBSCRIPTIONS AND PUBLISHED READINGS TO ADAFRUIT CLOUD MANUAL WATER BUTTON
void cloudData() {

   // Ping MQTT Broker every 2 minutes to keep connection alive
  if ((millis()-last)>120000) {
      Serial.printf("Pinging MQTT \n");
      if(! mqtt.ping()) {
        Serial.printf("Disconnecting \n");
        mqtt.disconnect();
      }
      last = millis();
  }
  // This is our 'wait for incoming subscription packets' busy subloop
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(1000))) {
    if (subscription == &waterButtonFeed) {
      waterValue = atoi((char *)waterButtonFeed.lastread);
      Serial.printf("Water Value %i \n", waterValue);
      if (waterValue == 1) {           //****MANUAL WATER PUMP****
        digitalWrite(WATERPIN,HIGH);
        Serial.printf("Pump is ON");
        delay(900);
        digitalWrite(WATERPIN,LOW);
      }
    }
  }

  if((millis()-lastTime > 30000)) { // PUBLISHES TO CLOUD
    if(mqtt.Update()) {
      moistureFeed.publish(soilMoisture);
      Serial.printf("Publishing Moisture %i\n", soilMoisture);

      temperatureFeed.publish(tempF);
      Serial.printf("Publishing Temp %0.1f\n", tempF);

      humidityFeed.publish(humidity);
      Serial.printf("Publishing Humidity %0.1f\n", humidity); 
      
      dustParticleFeed.publish(concentration);
      Serial.printf("Publishing Dust %i\n", concentration);

      airQualityFeed.publish(airSensor.getValue());
      Serial.printf("Publishing Air %i\n", airSensor.getValue() );

      } 
    lastTime = millis();
  }
  waterPump();
}

//Sets up water pump
void waterPump() {
  if(soilMoisture > 2700) {
    if ((millis()-pumpTimer)>30000) {
      digitalWrite(WATERPIN,HIGH);
      Serial.printf("Pump is ON \n");
      delay(700);
      digitalWrite(WATERPIN,LOW);
      Serial.printf("Pump is OFF \n");
      pumpTimer = millis();
    }
  }
}

//Dust detector 
void dustSensor() {
  duration = pulseIn(DUSTPIN, LOW);
  lowPulseOccupancy = lowPulseOccupancy+duration;

  if ((millis()-startTime) > sampleTime_ms) {
    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
    Serial.print(lowPulseOccupancy);
    Serial.print(",");
    Serial.print(ratio);
    Serial.print(",");
    Serial.println(concentration);
    lowPulseOccupancy = 0;
    startTime = millis();
  }
}
// Checks air quality and displays whether it is high or low
void airQualityCheck() {
  int quality = airSensor.slope();
  display.display();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(WHITE);        // Draw WHITE text
  display.setCursor(29,56);             // Start at bootom-left corner

  Serial.print("Air Sensor value: ");
  Serial.printf("%i\n", airSensor.getValue());
  if((millis()-lastTimeAir > 5000)) {
    if (quality == AirQualitySensor::FORCE_SIGNAL) {
      Serial.printf("High pollution! Force signal active.\n");
      display.printf("High Pollution!");
    }
    else if (quality == AirQualitySensor::HIGH_POLLUTION) {
      Serial.printf("High pollution!\n");
      display.printf("High Pollution!");
    }
    else if (quality == AirQualitySensor::LOW_POLLUTION) {
      Serial.printf("Low pollution!\n");
      display.printf("Low Pollution!");
    }
    else if (quality == AirQualitySensor::FRESH_AIR) {
      Serial.printf("Fresh air.\n");
      display.printf("Fresh Air!");
    }
    display.display();
    lastTimeAir = millis();
  }
}
    

Credits

Carli Stringfellow

Carli Stringfellow

3 projects • 3 followers
Hello! My name is Carli Stringfellow. I am a beginner developer gaining experience in electronics, hardware design, and C++ coding.

Comments

Add projectSign up / Login