Happy Watered Plant

Made by Langley Vogt

Found in DioT 2019: Internet of Plants

An IOT device that monitors the moisture level of one’s plant and depending on if the plant is adequately watered, the plant will light up and swivel around as a happy plant and cheer the owner up.

0

Solution

Keeping a plant’s water level satisfactory may be difficult to judge from just the appearance of the soil. With this IOT device, the soil-moisture level is easily visible by a red ( unsatisfactory ), green (satisfactory) or blue (very hydrated) LED and the exact measurement is logged in a spreadsheet where the plant owner can make sure the doing well. If the plant’s moisture level is below the set satisfactory level (may depend on the type of plant) and shines the red LED, an SMS notification will be sent to the plant owner’s mobile device reminding them to water the plant every ten minutes.

When the user is home, the plant owner can interact with the plant. By pressing a button, if the plant has an adequate water level, the plant will light up, play a tune, and swivel around to demonstrate it is a happy plant. If the water level is below satisfactory, a bad tone will be played and the plant will not dance around.

0

Approach

For this project, I wanted to go beyond checking the plant’s moisture level. Although it is important to keep your plant healthy and watered, I feel that adding something fun makes the experience more interactive and gives the user a sense of reward for taking care of their plant. The “dancing plant” idea was influenced by positive reinforcement from video games – for example, if you take care of a pet, their health or love for you will increase and they’ll smile or show you appreciation in some way. I wanted to create a subtle emotional attachment to the plant to potentially lengthen the lifespan of the plant.

The LED indicators were influenced by ambient design where a plant owner can just glance over at their plant and see if the plant needs water or not. This was similar to the umbrella that has a handle that indicates the weather outside and helps the user decide if the umbrella is needed at a quick glance at the glowing color [1].

0

Process

After I determined an overall idea of what I wanted my IOT device to do, as explained in my Approach above, I created tasks and subtasks to complete for each component, integrating them together as I went along. This is the order of how I assembled my final product:

          1. Pseudo-code and outline the hierarchy of the code (seen in workflow diagram)
          2. Learn how to use and wire a servo motor [3]
          3. Use prior knowledge and skills from in class Skills Dev to apply my DIY soil-moisture detector to this circuit
          4. Wire in LED’s (red = bad, green = good, blue = very saturated, yellow for decoration) and combine with the moisture detector and motor.
          5. Wire the piezoelectric speaker and determine melody and corresponding durations for notes to play when moisture level is satisfactory
          6. Determine tone to play for unsatisfactory moisture level
          7. Integrate into existing circuit
          8. Add pushbutton to activate happy plant dancing and short LED light show
          9. Create IFTTT recipe for publishing events to a Google spreadsheet
          10. Create IFTTT recipe for sending SMS reminders to the plant owner
          11. Brainstorm and sketch the form and apparatus that would house the plant and components
          12. Prototype the form with foam-core and integrate all the components

One of the ambitious ideas I rejected was because it was outside the scope of my project was a water pump to automatically water the plant if the moisture level was unsatisfactory. It apparently involved additional power sources and more advance techniques and took away from the user interaction. The other idea I did not pursue was constantly monitoring for a change in moisture level to detect when the user watered the plant and the moisture level went from unsatisfactory to satisfactory. The plant’s happy dance and lights would automatically start when that change was detected, but I chose a more simplistic path by adding a pushbutton to activate it.

The main challenge that I encountered was realizing that the code had to run sequentially and tasks could not be completed simultaneously. I wanted the LED’s, music and servo motor to work simultaneously, but instead, I solved this alternating LED illuminations, servo motor actions, and music. 

0
Workflow Diagram
Workflow
0

Implementation

Parts list:

  • Argon Particle Board with WIFI connector
  • DIY soil-moisture detector (2 uncoated nails, non-conductive spacer, wires)
  • Servo motor (SG51R)
  • Piezoelectric speaker
  • Pushbutton (4 prong)
  • LEDs (Red, Green, Blue, Yellow)
  • Five 1k resistors 
Demonstration video and code directly below, followed by pictures of the physical circuit and prototyped form.

0
Demo video of dancing plant
0
Particle IO Code
//Created by Langley Vogt
//https://diotlabs.daraghbyrne.me/docs/controlling-outputs-motors/servo/#step-2-controlling-a-servo
//https://docs.particle.io/tutorials/hardware-projects/maker-kit/

//CONSIDERED WATER LEVELS
//Good Example= 1327
//Bad < 800
//Very watered > 1800

int lowMoistThres = 600;
int highMoistThres = 1800;

//Define servo motor and name
Servo spinnerServo;
int servoPin = A0;
int servoPos = 0; //intialize at zero

//LED declarations
int ledGreen = D7;
int ledRed = D6;
int ledBlue = D5;
int ledYellow = D4;

//soil
int moistPin = A1;
int moistVal = 0;

//Speaker piezo
int speakerPin = D2;

//push button
int buttonPin = D8;
int buttonState;

//Note Definitions
int NOTE_C = 1046;
int NOTE_D = 1174;
int NOTE_E = 1318;

int lowNOTE_C = 1046/2;
int lowNOTE_E = 1318/2;

int yayMelody[] = {NOTE_C, NOTE_C, NOTE_C, NOTE_C, NOTE_D, NOTE_C, NOTE_D, NOTE_E};
int noteDuration[] = {4, 8, 8, 4, 4, 4, 4, 2};

int badMelody[] = {lowNOTE_E, lowNOTE_C};
int noteDuration2[] = {2, 2};

// store the last time published
int last_published = -1;
int last_publishedSMS = -1;

//*********************************************************************//
void setup() {
    //Define which pin the servo is connected to
    spinnerServo.attach(A0);
    
    //Call function so person can enter angle on app
    Particle.function("servo", servoControl); //control via cloud
    
    //Push variable to console
    Particle.variable("MoistureReading", moistVal);
    Particle.variable("buttonState", buttonState);

    //Declare led as output
    pinMode(ledGreen, OUTPUT);
    pinMode(ledRed, OUTPUT);
    pinMode(ledBlue, OUTPUT);
    pinMode(ledYellow, OUTPUT);

    //Initialize leds off
    digitalWrite(ledRed, LOW);
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledBlue, LOW);
    digitalWrite(ledYellow, LOW);

    //define pin mode input/ouputs for non-leds
    pinMode(moistPin, INPUT);
    pinMode(buttonPin, INPUT_PULLUP);
    
}

void loop() { 
    
    //send published data to spreadsheet every minute
    writeToSpreadsheet();
    
    //initialize led lights off
    digitalWrite(ledRed, LOW);
    digitalWrite(ledGreen, LOW);
    digitalWrite(ledBlue, LOW);
    digitalWrite(ledYellow, LOW);

    //Variable definitions
    moistVal = analogRead(moistPin);
    buttonState = digitalRead(buttonPin);

    //if the soil is not moist enough, shine red led
    if (moistVal < lowMoistThres) {
        digitalWrite(ledRed, HIGH);
        delay(100);
        
        //send SMS to remind user to water plant
        sendSMS();
    }
    //Soil is adequately moist, green
    else if (moistVal > lowMoistThres && moistVal < highMoistThres) {
        //digitalWrite(ledPin, HIGH);
        digitalWrite(ledGreen, HIGH);

        delay(100);
    }
    //Very moist soil, blue light indicator
    else if (moistVal > highMoistThres) {
        //digitalWrite(ledPin_3, HIGH);
        digitalWrite(ledBlue, HIGH);

        delay(100);
    }
    //else just turn off all the lights
    else {        
        digitalWrite(ledGreen, LOW);
        digitalWrite(ledRed, LOW);
        digitalWrite(ledBlue, LOW);
        digitalWrite(ledYellow, LOW);
    }
    
    
    //If the user presses the button and the plant was watered adequately, flash lights, play music and spin
    if ( (moistVal > lowMoistThres) && (buttonState == LOW)) {

        //flash lights
        digitalWrite(ledRed, HIGH);
        delay(300);
        digitalWrite(ledGreen, HIGH);
        delay(300);
        digitalWrite(ledBlue, HIGH);
        delay(300);
        digitalWrite(ledYellow, HIGH);
        delay(300);
        
        //flash lights
        digitalWrite(ledRed, LOW);
        delay(300);
        digitalWrite(ledGreen, LOW);
        delay(300);
        digitalWrite(ledBlue, LOW);
        delay(300);
        digitalWrite(ledYellow, LOW);
        delay(300);   
        
        //play melody
        playNotes();

        //flash lights
        digitalWrite(ledRed, HIGH);
        delay(300);
        digitalWrite(ledGreen, HIGH);
        delay(300);
        digitalWrite(ledBlue, HIGH);
        delay(300);
        digitalWrite(ledYellow, HIGH);
        delay(300);
        
        //flash lights
        digitalWrite(ledRed, LOW);
        delay(300);
        digitalWrite(ledGreen, LOW);
        delay(300);
        digitalWrite(ledBlue, LOW);
        delay(300);
        digitalWrite(ledYellow, LOW);
        delay(300);    
        
        //turn all on
        digitalWrite(ledRed, HIGH);
        digitalWrite(ledGreen, HIGH);
        digitalWrite(ledBlue, HIGH);
        digitalWrite(ledYellow, HIGH);

        //Swivel forward
        for (int angle = 0; angle < 180; angle++) {
            spinnerServo.write(angle);
            delay(10);
        }
        //pause
        delay(200);
        
        //Swivel backward
        for (int angle2 = 180; angle2 > 0; angle2--) {
            spinnerServo.write(angle2);
            delay(10);
        }
        delay(100);
        
        //Spin faster, 2 rounds
        spinnerServo.write(90);
        delay(800);
        
        spinnerServo.write(0);
        delay(800);
        
        spinnerServo.write(90);
        delay(800);
        
        spinnerServo.write(0);
        delay(800);
        
        //turn all on
        digitalWrite(ledRed, LOW);
        digitalWrite(ledGreen, LOW);
        digitalWrite(ledBlue, LOW);
        digitalWrite(ledYellow, LOW);
        
        //flash lights
        digitalWrite(ledRed, HIGH);
        delay(300);
        digitalWrite(ledGreen, HIGH);
        delay(300);
        digitalWrite(ledBlue, HIGH);
        delay(300);
        digitalWrite(ledYellow, HIGH);
        delay(300);
        
        //flash lights
        digitalWrite(ledRed, LOW);
        delay(300);
        digitalWrite(ledGreen, LOW);
        delay(300);
        digitalWrite(ledBlue, LOW);
        delay(300);
        digitalWrite(ledYellow, LOW);
        delay(300);      
        
        delay(100);
        
    }
    //Button pressed but not enough moisture
    else if ((moistVal < lowMoistThres) && (buttonState == LOW)) {
        //change light to yay
        digitalWrite(ledRed, LOW);
        delay(10);
        digitalWrite(ledRed, LOW);
        delay(10);
        digitalWrite(ledRed, LOW);
        
        playBadNotes();
        
        delay(100);
    }
    else {
        //do nothing
    }
    
    delay(100);
}

//Melody that plays when plant is watered adequately
void playNotes()
{
    //for loop for melody, total 26 notes 
    for (int thisNote = 0; thisNote < 8; thisNote++) {

      // to calculate the note duration, take one second
      // divided by the note type.
      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
      int newNoteDurations = 1000/noteDuration[thisNote];
      tone(speakerPin, yayMelody[thisNote],newNoteDurations);

      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = newNoteDurations * 1.30;
      delay(pauseBetweenNotes);
      
      //no tone
      noTone(speakerPin);
    }
}

void playBadNotes()
{
    //for loop for melody, total 26 notes 
    for (int thisNote2 = 0; thisNote2 < 2; thisNote2++) {

      // to calculate the note duration, take one second
      // divided by the note type.
      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
      int newNoteDurations2 = 1000/noteDuration2[thisNote2];
      tone(speakerPin, badMelody[thisNote2],newNoteDurations2);

      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes2 = newNoteDurations2 * 1.30;
      delay(pauseBetweenNotes2);
      
      //no tone
      noTone(speakerPin);
    }
}

//Have user set angle for viewing position
int servoControl (String command) {
    int newPos = command.toInt();
    servoPos = constrain(newPos, 0, 180);
    
    spinnerServo.write(servoPos);
    
    return 1;
}

//Write data to spreadsheet
void writeToSpreadsheet() {

  // check if 1 minute has elapsed
	if( last_published + 60000 < millis() ){
		Particle.publish( "writeToSpreadsheet", String(moistVal) );
		last_published = millis();
	}
}

//Notify plant owner via text message that their plant is thirsty
void sendSMS() {
    
  // check if 1 minute has elapsed
  //10 minutes is 6e8
	if( last_publishedSMS + 60000 < millis() ){
		Particle.publish( "sendSMS", String("Water your Plant!") );
		last_publishedSMS = millis();
	}
}
Click to Expand
0

IFTTT Applets below.

0
IFTTT Applets
Applets
0
IFTTT App Notifications
Ifttt app
0
Google Sheets published data with event | moisture level | device | date and time
Spreadsheet data 02
0

Next Steps

Next steps could include implementing code that detects when the user has watered the plant adequately to trigger the happy plant dance. An upgraded servo motor, or even a torque motor, would make the swiveling quieter, less jerky and support heavier plants.

The form was prototyped, but I would like the final form of the apparatus to be made of wood, hide all of the wires so only the LED’s are visible on the wood’s surface for a minimalist, ambient aesthetic.

Lastly, a live dashboard accessible through a plant monitoring application that can be viewed on one’s mobile phone would enable the plant owner to monitor the plant’s moisture level easily throughout the day. It could also have fun functions that play different music melodies and activate various dances for the plant. 


0

Reflection

This was a very enjoyable project and I had a lot of fun making a more interactive plant that would lift the plant owner’s mood. I have not worked a servo motor before so I was able to quickly learn those skills, learn the limitations, adjust, and apply them to this project.

I learned simplistically “enchanting” an analog object can elevate the overall experience and interaction with it. As a student, this project was definitely a good stepping stone towards a larger, more involved IOT project where form is required. This project emphasized conceptual ideas and basics to prepare me to execute more complex projects.

0

References

  1. Ambient Umbrella: https://www.geeky-gadgets.com/the-ambient-umbrella-30-12-2009/
  2. Inspiration for owner interaction with music (discovery): https://particle.hackster.io/make-photons-great-again/motion-activated-music-player-ad8878
  3. Servo Motor: https://docs.particle.io/tutorials/hardware-projects/maker-kit/
  4. Tutorials: https://diotlabs.daraghbyrne.me/
  5. Circuit Diagram Software: https://fritzing.org/home/

x
Share this Project

Courses

49713 Designing for the Internet of Things

· 16 members

A hands-on introductory course exploring the Internet of Things and connected product experiences.


Focused on
About

An IOT device that monitors the moisture level of one’s plant and depending on if the plant is adequately watered, the plant will light up and swivel around as a happy plant and cheer the owner up.

Created

November 6th, 2019