Mamie-Jo Beatty
Published © MIT

House Plant Watering System

This project is a house plant watering system that will automatically water your plant when the soil becomes too dry.

IntermediateShowcase (no instructions)Over 1 day40
House Plant Watering System

Things used in this project

Hardware components

Photon 2
Particle Photon 2
×1
Fermion: Multi-function Environmental Module - CCS811+BME280 (Breakout)
DFRobot Fermion: Multi-function Environmental Module - CCS811+BME280 (Breakout)
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Grove - Capacitive Soil Moisture Sensor
Seeed Studio Grove - Capacitive Soil Moisture Sensor
×1
Grove - Air quality sensor v1.3
Seeed Studio Grove - Air quality sensor v1.3
×1
Relay (generic)
×1

Software apps and online services

Bambu Labs
Solidworks

Hand tools and fabrication machines

Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Custom parts and enclosures

Water Bowl

Pot Base

Sketchfab still processing.

Breadboard Stand

Sketchfab still processing.

Schematics

Adafruit Dashboard

Fritzing

Schematics and Project Planning

Schematics and Project Planning

Schematics and Project Planning

Schematics and Project Planning

Code

House Plant WS Code

C/C++
#include "Particle.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"
#include "Adafruit_BME280.h"
#include "Grove_Air_Quality_Sensor.h"
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "credentials.h"

TCPClient TheClient; 

Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY); 

//***** feeds *****//

Adafruit_MQTT_Publish tempFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temp");
Adafruit_MQTT_Publish humidFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humid");
Adafruit_MQTT_Publish aqFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/aq");
Adafruit_MQTT_Publish moistureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/moisture");
Adafruit_MQTT_Subscribe subFeed = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/waterButton"); 

AirQualitySensor sensor(A2);    // AQ SENSOR AT A2

unsigned int lastTime;
const int OLED_RESET = -1;
const int moisturePin = A1;    // CAPACITATOR AT A1
const int hexAddress = 0x76;  // BME ADDRESS

bool buttonState;

int PUMP = D16;
int moistureLevel;
int moisture;

const char degree = 248;

int status;
int count;

float temp;       
float humid;
float pressure;
float subValue,pubValue;

void MQTT_connect();
bool MQTT_ping();

Adafruit_SSD1306 display(OLED_RESET);
Adafruit_BME280 bme;

String getMoistureStatus(int moisture);
String dateTime, timeOnly;

SYSTEM_MODE(AUTOMATIC);


SYSTEM_THREAD(ENABLED);


SerialLogHandler logHandler(LOG_LEVEL_INFO);


void setup() {

  Time.zone(-7);           //TIME STAMP IN MOUNTAIN TIME 
  Particle.syncTime();

  pinMode(PUMP, OUTPUT);

// TURN ON WIFI AND CONNECT TO THE INTERNET // 
    WiFi.on();
  WiFi.connect();
  while(WiFi.connecting()) {
    Serial.printf(".");
  }
  Serial.printf("\n\n");

  // Setup MQTT subscription
  mqtt.subscribe(&subFeed);

  Serial.begin(9600);
  waitFor(Serial.isConnected, 10000);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  delay(100);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(1,0);
  display.setRotation(3);
  display.setCursor(0,0);
  display.display();

  // START BME SENSOR //

  status = bme.begin(hexAddress);
  if(status == false){
    Serial.printf("BME280 at address 0x%02x failed to start \n", hexAddress);
  }

  pinMode(moisturePin, INPUT);
  mqtt.subscribe(&subFeed);
}


void loop() {

  MQTT_connect();
  MQTT_ping();

  // SUBSCRIPTION INFORMATION FOR DASHBOARD BUTTON //

   Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(100))) {
    if (subscription == &subFeed) {
      buttonState = atof((char *)subFeed.lastread);
      Serial.printf("Button state: %i\n", buttonState);
    }
  }

  // AUTO AND MANUAL WATERING CODE //

if(moisture > 3000) {                   // AUTO //
  digitalWrite(PUMP, HIGH);
  display.printf("WATERING ... \n");
  delay(500);
  digitalWrite(PUMP,LOW);
  display.printf("QUENCHED...\n");
  delay(500);
}


if (buttonState == 1)                // MANUAL - DASHBOARD //
{
  digitalWrite(PUMP, HIGH);
}
if (buttonState == 0)
{
  digitalWrite(PUMP, LOW);
}

   // CAPACITATOR AND TIME STAMP//
   
 moistureLevel = analogRead(moisturePin);
 Serial.printf(String(moistureLevel));
 String moistureStatus = getMoistureStatus(moistureLevel);
 String currentTime = Time.format(Time.now(), "%H:%M:%S");
 //display.setCursor(0,0);
 display.print("Time: ");
 display.printf(currentTime);
 display.print("Moisture: ");
 display.printf(String(moistureLevel));
 display.display();

 dateTime = Time.timeStr();
 timeOnly = dateTime.substring(11,19);
 if(millis()-lastTime>10000) {
  lastTime = millis();

  Serial.printf("Date and time is %s\n", dateTime.c_str());
  Serial.printf("Time is %s\n", timeOnly.c_str());
 }

 // BME //
temp = bme.readTemperature();
humid = bme.readHumidity();
pressure = bme.readPressure();

  Serial.printf("temp = %0.1f, humid = %0.1f, press = %0.1f \n", temp, humid, pressure);
  //display.setCursor(0,10);
  display.printf("temp = %0.1f, humid = %0.1f, pressure = %0.1f \n", temp, humid, pressure);
  display.display();
  delay(100);

  // PUBLISHING DATA TO DASHBOARD //
  
  if((millis()-lastTime > 10000)) {
    if(mqtt.Update()) {
      tempFeed.publish(temp);
      Serial.printf("Publishing %0.1f \n", temp); 
      humidFeed.publish(humid);
      Serial.printf("Publishing %0.1f \n", humid);
      moistureFeed.publish(moistureLevel);
      Serial.printf("Publishing %i\n", moistureLevel);
      //aqFeed.publish(sensor);
      } 
    lastTime = millis();
  }

// AIR QUALITY SENSOR //
int quality = sensor.slope();

Serial.print("Sensor value: ");
Serial.printf("%i\n", sensor.getValue());

if(quality == AirQualitySensor::FORCE_SIGNAL) {
  Serial.printf("I CAN'T BREATHE D: \n");
  //display.setCursor(0, 40);
  display.printf("I CAN'T BREATHE D: \n");
  display.display();
}
if(quality == AirQualitySensor::HIGH_POLLUTION){
  Serial.printf("I could use some oxygen rn :/ \n");
  //display.setCursor(0, 40);
  display.printf("I could use some oxygen rn :/ \n");
  display.display();
}
if(quality == AirQualitySensor::LOW_POLLUTION){
  Serial.printf("I could be breathing better :| \n");
  //display.setCursor(0, 40);
  display.printf("I could be breating better :| \n");
  display.display();
}
if(quality == AirQualitySensor::FRESH_AIR){
  Serial.printf("*INHALE EXHALE* Ahhhhh \n");
  //display.setCursor(0, 40);
  display.printf("*INHALE EXHALE* Ahhhhh \n");
  display.display();
}
//delay(100);

}

// READ MOISTURE LEVELS TO DETERMINE WHEN THE PLANT NEEDS WATER, USE FUNCTION IN LOOP
String getMoistureStatus(int moisture) {
  if(moisture > 3000) {
    return "Thirsty";
  }
  if(moisture <= 2999) {
    return "Thank you";
  }
  else{
    return "TOO MUCH AHHHHHH";
  }
}

// MQTT CODE FOR CONNECTING TO ONLINE DASHBOARD //

void MQTT_connect() {
  int8_t ret;
 
  // Return if already connected.
  if (mqtt.connected()) {
    return;
  }
 
  Serial.print("Connecting to MQTT... ");
 
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.printf("Error Code %s\n",mqtt.connectErrorString(ret));
       Serial.printf("Retrying MQTT connection in 5 seconds...\n");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds and try again
  }
  Serial.printf("MQTT Connected!\n");
}

bool MQTT_ping() {
  static unsigned int last;
  bool pingStatus;

  if ((millis()-last)>120000) {
      Serial.printf("Pinging MQTT \n");
      pingStatus = mqtt.ping();
      if(!pingStatus) {
        Serial.printf("Disconnecting \n");
        mqtt.disconnect();
      }
      last = millis();
  }
  return pingStatus;
}

Credits

Mamie-Jo Beatty
3 projects • 6 followers
Contact

Comments

Please log in or sign up to comment.