Jessica Rodriquez
Published © MIT

Smart Plant Watering System

This is a smart watering system I made for my second midterm project as part of CNM's IoT bootcamp curriculum.

IntermediateFull instructions provided3 days1,060
Smart Plant Watering System

Things used in this project

Story

Read more

Custom parts and enclosures

Flower Pot

GitHub repository

Schematics

Fritzing

How is it wired

Schematic for plant watering

Code

Code for Smart Plant Watering

C/C++
Great code to water a plant with!
/*
 * Project Midterm2_Plant_Watering_System
 * Description: Smart watering system
 * Author:Jessica Rodriquez
 * Date:9-NOV-2021
 */


// SYSTEM_MODE (SEMI_AUTOMATIC);

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BME280.h>
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT.h" 
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Grove_Air_quality_Sensor.h"


#include "credentials.h"

#define OLED_RESET D4
#define BME_ADDRESS 0x76
#define MOTORPIN 11
#define DUST_PIN A2

Adafruit_SSD1306 display(OLED_RESET);
Adafruit_BME280 bme;
AirQualitySensor airQuality(A3);

TCPClient TheClient; 

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

Adafruit_MQTT_Publish mqttObjSoil = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/SoilMoisture");
Adafruit_MQTT_Publish mqttObjTempF = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/RoomTemp");
Adafruit_MQTT_Publish mqttObjPressure = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Pressure");
Adafruit_MQTT_Publish mqttObjHumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Humidity");
Adafruit_MQTT_Publish mqttObjDust = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Dust");
Adafruit_MQTT_Publish mqttObjAQ = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/AQ");

Adafruit_MQTT_Subscribe mqttObjPumpOn = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/OnOff");

/************Declare Variables*************/
int airQualityValue, moistureReadings;

bool status;

float tempC;
float tempF;
float pressPA;
float pressInHg;
float humidRH;


unsigned long last, lastTime, startPumpTime, duration, starttime;
unsigned long sampletime_ms = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;

String DateTime, TimeOnly, DateOnly;

void setup() {
  Serial.begin(9600);
  waitFor(Serial.isConnected, 15000);

  startBME();
  airQuality.init();
  pinMode(A1,INPUT);
  pinMode(11,OUTPUT);

  startDisplay();

  startWifi();

// Setup MQTT subscription for onoff feed.
  mqtt.subscribe(&mqttObjPumpOn);
  Time.zone(-7);
  Particle.syncTime();
}                                                         

void loop() {
  // Validate connected to MQTT Broker
  MQTT_connect();
  // Ping MQTT Broker every 2 minutes to keep connection alive
  pingMQTT();

  moistureReadings=analogRead(A1);
  if((millis()-lastTime>10000)) {
    if(mqtt.Update()) {
     printMoisture(moistureReadings);
     publishMoisture(moistureReadings);
     tempC = bme.readTemperature();
     showBME(tempC);
     pressPA = bme.readPressure();
     showPress(pressPA);
     humidRH = bme.readHumidity();
     showHum(humidRH);
     checkDust();
     checkAQ();
     printTime();
     } 
    lastTime = millis();
  }

  pumpOn(moistureReadings,getbuttonvalue());
  pumpOff();
}

void startBME() {
  status = bme.begin(BME_ADDRESS);
  if (status == false) {
    Serial.printf ("BME at address 0x%02X failed to start", BME_ADDRESS);
  }
}

void startDisplay() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.display();
}

void startWifi() {
  WiFi.connect();
  if(WiFi.connecting()) {
    Serial.printf("Trying to connect to Wifi...\nOne moment please...\n");
  }
  while (WiFi.connecting()) {
    //waiting for wifi to connect
  }
}

// Function to connect and reconnect as necessary to the MQTT server.
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.printf("%s\n",(char *)mqtt.connectErrorString(ret));
       Serial.printf("Retrying MQTT connection in 5 seconds..\n");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
  }
  Serial.printf("MQTT Connected!\n");
} 

void pingMQTT() {
    // 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();
  }
}

void printMoisture(int _moistureReadings) {
  Serial.printf("Soil Moisture %i\n",_moistureReadings);
  display.setCursor(0,0);             // Start at top-left corner
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(BLACK,WHITE); // Draw 'inverse' text
  display.printf("Soil Moisture %i\n",_moistureReadings);
  display.display();
}

void publishMoisture(int _moistureReadings) {
      mqttObjSoil.publish(_moistureReadings);
      Serial.printf("Publishing Soil %i \n",_moistureReadings); 
}

void showBME(float _tempC) {
  tempF = (_tempC * 9 / 5) + 32;
  Serial.printf ("temp %f \n", tempF);
  display.printf ("temp %0.1f \n", tempF);
  display.display();

  mqttObjTempF.publish(tempF);
  Serial.printf("Publishing Temp %0.2f \n",tempF); 
}

void showPress(float _pressPA) {
  pressInHg = (_pressPA / 3386);
  Serial.printf("pressure %f \n", pressInHg);
  display.printf ("pressure %0.2f \n", pressInHg);
  display.display();
  
  mqttObjPressure.publish(pressInHg);
  Serial.printf("Publishing Press %0.2f \n",pressInHg); 
}

void showHum(float _humidRH) {
  Serial.printf("humidity %f \n", _humidRH);
  display.printf("humidity %0.1f \n", _humidRH);
  display.display();

  mqttObjHumidity.publish(_humidRH);
  Serial.printf("Publishing Hum %0.2f \n",_humidRH); 
}

void checkDust() {
  duration = pulseIn(DUST_PIN, 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
      lowpulseoccupancy = 0;
      starttime = millis();
    }
    Serial.printf("Dust Concentration: %f\n", concentration);
    mqttObjDust.publish(concentration);
    Serial.printf("Publishing Dust %0.2f \n",concentration);
    display.printf("Dust %0.3f \n", concentration);
    display.display();
}

void checkAQ() {
  airQualityValue = airQuality.getValue();
  display.printf("Air Qual %i \n", airQualityValue);
  display.display();
  mqttObjAQ.publish(airQualityValue);
  Serial.printf("Publishing Air Qual %i\n",airQualityValue);
}

void printTime() {
   TimeOnly = Time.timeStr().substring(11,16);
   DateOnly = Time.timeStr().substring(4,10);
   display.printf("Time:%s\n",TimeOnly.c_str());
   display.printf("Date:%s\n",DateOnly.c_str());
   DateTime = Time.timeStr();
   Serial.printf("Date String %s\n", DateTime.c_str());
}

int getbuttonvalue(){
  int buttonvalue = 0;
Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(1000))) {
    if (subscription == &mqttObjPumpOn) {
      buttonvalue = atoi((char *)mqttObjPumpOn.lastread);
      Serial.printf("Received %i from Adafruit.io feed OnOff \n", buttonvalue);
    }
  }
  return buttonvalue;
}


//Function to get motor turning on every half second
void pumpOn(int moistureReadings, int buttonvalue){
  Serial.printf("pump on\n");
  if(moistureReadings > 3446||buttonvalue) {
    digitalWrite(MOTORPIN,HIGH);
    startPumpTime=(millis());
  }
}

void pumpOff () { 
  Serial.printf("pump off\n");
  if (millis()-startPumpTime>2000) {
    digitalWrite(MOTORPIN, LOW);
  }
}
 

Credits

Jessica Rodriquez

Jessica Rodriquez

5 projects • 10 followers

Comments