Nick Stanley
Published © GPL3+

Plantbot Soil Management

Automated soil moisture management

IntermediateShowcase (no instructions)8 hours1,885
Plantbot Soil Management

Things used in this project

Hardware components

Photon
Particle Photon
×1
Particle Power Sheild
×1
Particle WiFi Duck Antenna
×1
SparkFun Solar Panel - 6V 6W
×2
SparkFun Motor Driver - Dual TB6612FNG (1A)
SparkFun Motor Driver - Dual TB6612FNG (1A)
×1
SparkFun Soil Moisture Sensor (with Screw Terminals)
SparkFun Soil Moisture Sensor (with Screw Terminals)
×1
SparkFun Big Red Box Enclosure
×1
SparkFun Big Red Box Proto Board
×1
Solar Battery Tender
×1
12V Lead Acid Battery
×1

Software apps and online services

Ubidots
Ubidots

Story

Read more

Schematics

Wiring Diagram

Code

Plantbot.ino

C/C++
/*
 * Plantbot.ino
 * Author: Nick Stanley
 * 
 * This program reads a soil moisture sensor and activates a water pump if necessary
 * The system's power source runs the pump or charges a Li-Po battery. The system power is a 12V lead acid battery
 * charged by a solar panel. 
 * Data is reported to Ubidots for monitoring. A text message will be sent by Ubidots if the water level is low.
 * A text message will also be sent by IFTTT after 6pm if the water is low. I'll be home after 6, so it would be a
 * better reminder than getting a text while I'm busy at work
 *
 * See www.hackster.io/nick-stanley/particle-photon-plantbot for full documentation
 *
 * Ubidots.h: Mateo Velez
 * PowerShield.h: Luca Dentella, Mohit Bhoite
 * 
 */

/*
Copyright (c) 2013-2016 Ubidots.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Made by Mateo Velez - Metavix for Ubidots Inc
*/
#include "Ubidots/Ubidots.h"

// 
// PowerShield.h
// Library for the Particle Power Shield
// Based on original library published by Luca Dentella (http://www.lucadentella.it)
// Modified by Mohit Bhoite @ Particle Industries, Inc. July 2015
// Power Shield Documentation: http://docs.particle.io/photon/shields/#power-shield
// MAX17043 datasheet: http://datasheets.maximintegrated.com/en/ds/MAX17043-MAX17044.pdf
//
#include "PowerShield/PowerShield.h"

#include "application.h"

SYSTEM_MODE(SEMI_AUTOMATIC)

//Pin Definition
/* Powersheild uses I2C pins
#define BATTERY_MONITOR_SDA D0
#define BATTERY_MONITOR_SCL D1 */
#define SOLAR_PUMP_PIN D2       //HIGH to route power to pump, LOW to kill power to pump
#define WATER_LEVEL_PIN D3      //Active low switch, HIGH for full, LOW for empty
#define SOLAR_CHARGE_PIN D4     //HIGH to route power to battery shield, LOW to kill power to battery shield
#define SOIL_MOISTURE_PIN A0    //Variable resistor for soil moisture, higher value = more moisture

//Constants
#define FIVE_MINUTES 300            //5 mins * 60 seconds/min = 300 seconds
#define FIFTEEN_MINUTES 900         //15 mins * 60 seconds/min = 900 sedonds
#define FIFTEEN_HOURS 54000         //15 hr * 60 min/hr * 60 seconds/min = 54000 seconds
#define DESIRED_MOISTURE_LEVEL 3050 //Found experimentally, 3200 should keep it watered most of the day
#define UBITOKEN "jIelpYm8e8vDF5KeZ9Xi3eKNa8ehJI"

// Ubidots Cloud data management, see Ubidots.h
Ubidots ubidots(UBITOKEN);

//Particle PowerShiled monitoring, see PowerShield.h
PowerShield batteryMonitor;

//Variables
bool waterMessageSent = false;  //Have se sent a message today?
bool waterEmpty = false;        //Is the water tank empty?
bool sprinklerRunning = false;  //Is the water pump running?
bool batteryCharging = false;   //Are we charging the battery?
bool chargeNecessary = false;   //Does the battery have sufficient charge?
int moistureLevel;              //Mositure value, 0-4096, 2800-3300 typical
long offTime;                   //How often the program will check the sensors and report data
float batteryLevel;             //The State of Charge of the battery, see PowerShield.h


/*
 * ActivateSprinkler()
 *
 * Kill the power route from Solar to Photon Battery
 * Route the Solar power to Water Pump
 */
void ActivateSprinkler()
{
    //Break before make!
    //Route solar panel away from charger
    digitalWrite(SOLAR_CHARGE_PIN, LOW);
    
    //Route solar panel to motor
    digitalWrite(SOLAR_PUMP_PIN, HIGH);
    
    //Five minutes of watering should be sufficient
    offTime = FIVE_MINUTES;
    sprinklerRunning = true;
    batteryCharging = false;
}

/*
 * DeactivateSpinkler()
 *
 * Kill the power route from Solar to Water Pump
 * Route the Solar power to Photon Battery if need be
 */
void DeactivateSprinkler()
{
    //Break before make!
    //Route solar panel away from motor
    digitalWrite(SOLAR_PUMP_PIN, LOW);
    
    //Route solar panel to charger if needed
    if(chargeNecessary)
    {
        digitalWrite(SOLAR_CHARGE_PIN, HIGH);
        batteryCharging = true;
    }
    else
    {
       digitalWrite(SOLAR_CHARGE_PIN, LOW);
        batteryCharging = false; 
    }
    
    //We'll check-in again in fifteen minutes
    offTime = FIFTEEN_MINUTES;
    sprinklerRunning = false;
}

/*
 * KillPower()
 *
 * Do not route any Solar Power
 * Used at night to retain Solar Battery charge
 */
void KillPower()
{
    //Kill all power routes
    digitalWrite(SOLAR_PUMP_PIN, LOW);
    digitalWrite(SOLAR_CHARGE_PIN, LOW);
    
    offTime = FIFTEEN_HOURS;
    sprinklerRunning = false;
    batteryCharging = false;
}

/*
 * setup()
 *
 * Pin modes, battery I2C, time
 */
void setup() 
{
    //Water level active low
    pinMode(WATER_LEVEL_PIN, INPUT_PULLUP);
    
    //Power routing outputs
    pinMode(SOLAR_PUMP_PIN, OUTPUT);
    pinMode(SOLAR_CHARGE_PIN, OUTPUT);
    
    //Battery monitor
    // This essentially starts the I2C bus
    batteryMonitor.begin(); 
    // This sets up the fuel gauge
    batteryMonitor.quickStart();
    // Wait for it to settle down
    delay(500);
    
    DeactivateSprinkler();
}

/*
 * loop()
 *
 * Read sensors
 * Act on sensor data
 * Report to Ubidots
 * Check again in 5 or 15 minutes
 */
void loop() 
{
    //Make sure we're connected so we can update Ubidots
    Particle.connect();
    waitUntil(Particle.connected);
    //Particle.process();
    
    //
    //Check the battery. Don't charge unless we need to
    //The solar panel is charging a 12V 7A 20HR battery that can handle
    //the load, but we might as well give it break
    //
    batteryLevel = batteryMonitor.getSoC();
    if(batteryLevel < 30)
    {
        chargeNecessary = true;
    }
    if(batteryLevel > 90)
    {
        chargeNecessary = false;
    }
    
    //
    //Water level
    //
    if(digitalRead(WATER_LEVEL_PIN) == LOW)
    {
        waterEmpty = true;
    }
    else
    {
        waterEmpty = false;
    }
    
    //
    //Moisture Detection
    //
    moistureLevel = analogRead(SOIL_MOISTURE_PIN);
    if((moistureLevel < DESIRED_MOISTURE_LEVEL) && !waterEmpty)
    {
        ActivateSprinkler();
    }
    else
    {
        DeactivateSprinkler();
    }
    
    //
    //Report to Ubidots
    //
    ubidots.add("BatteryCharging", batteryCharging);
    ubidots.add("WaterAvailable", !waterEmpty);
    ubidots.add("MoistureLevel", moistureLevel);
    ubidots.add("SprinklerOn", sprinklerRunning);
    ubidots.add("BatteryLevel", batteryLevel);
    ubidots.sendAll();
    
    //
    //Sleep
    //
    WiFi.off();
    delay(offTime*1000); //offTime is stored as seconds, delay() requires milliseconds
}

Credits

Nick Stanley

Nick Stanley

5 projects • 13 followers
Software Engineer - System Integrator - Maker of Things

Comments