Before it escalates

Made by ziruiliu

Found in DioT 2019: Internet of Plants

Combine multiple, progressive layers of reminder for plant watering, from ambient display all the way to breaking into your working environment



My solution is to combine multiple, progressive layers of reminder for plant watering, from ambient display all the way to breaking into your working environment. At first, the device will simply use a non-intrusive LED signal to indicate the need for watering. When the user gets closer to the plant, the device will make sounds for a further reminder. When not being watered for one day, the plant(the device) will send an email to remind you again(shown below). Finally, when staying dried for 3 days(or longer), the plant snaps, straight up sending a post announcing your atrocity towards it on your personal website, which greatly affects your professional image (shown below) .


Demo video


Email reminders


Wordpress posts



My design approach is based on the Iterative thinking process, beginning with a basic function that addresses the problem, and then imagine how the plant can interact with its owner in multiple stages in order to add up other ideas also by considering different use cases(distant or close observation of the plant & checking emails or using Internet browsers).



Components used: Particle Argon, breadboard (generic), jumper wires, soil moisture sensor, 1K resistor, LED (generic), piezo, PIR Motion Sensor (generic).

Circuits assembled:  (shown below)

Challenges: 1. Difficulty setting proper timing for codes of different sensors. For instance, we need real-time updates of the sensors’ input data for timely feedback, while intervals are also needed to prevent publishing events too frequently(which may cause IFTTT to reach use limits).

2.Not familiar with the usage and sensitivity of the PIR sensor.

3. A proper design integrating different sensors into a progressive combination instead of being simply put together.

Solution: 1. Use the ‘if( last_published + 60000 < millis() )’ condition instead of ‘delay()’ to allow parallel processing of the sensor’s activity.

2. Go over a separate tutorial project to learn how the PIR sensor works.

3. An iterative process of letting different sensors ‘talk’ to each other to form an integrated system.



Completed code: (shown below)

Circuit diagram:  (shown below)


 - Particle Argon *1

 - breadboard (generic) *1

 - Jumper wires *11

 - Soil moisture sensor *1

 - 1K resistor *1

 - LED (generic) *1

 - Piezo *1

 - PIR Motion Sensor (generic) *1


Completed code

int last_published = -1;//event publish record 

//Initialize variables and set pins

int thresholdUp = 3000; 
int thresholdDown = 350;
int sensorPin = A0;
int sensorValue=0;

// Sketch for Particle Photon - PIR Sensor / Motion Detection
int inputPin = D4;              // choose the input pin (for PIR sensor)
int ledPin = D0;                // LED Pin
int pirState = LOW;             // we start, assuming no motion detected
int val = 0;                    // variable for reading the pin status

int calibrateTime = 1000;      // wait for the thingy to calibrate
bool shouldLedOn=false;

int speakerPin = D2;

// create an array for the notes in the melody:
int melody[] = {1908,2024}; 

// create an array for the duration of notes.
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {4,4};

int dryDay=0;//record the number of days that I haven't water the plant

void setup(){
 pinMode(sensorPin, INPUT);
 Particle.variable("moisturemoisture level", &sensorValue,INT);
  Particle.variable("drydays", &dryDay,INT);

 //digitalWrite(sensorVoltage, HIGH);
 pinMode(ledPin, OUTPUT);
    pinMode(inputPin, INPUT);     // declare sensor as input

// Sensor Readings

void loop()

// if the sensor is calibrated
  if (calibrated()) {
  // get the data from the sensor
    // report it out, if the state has changed



void updateMoisture(){
    sensorValue = analogRead(sensorPin);
    if (sensorValue > thresholdUp){
        	if( last_published + 60000 < millis() ){//use one minute to simulate a day
    Particle.publish("SoilStatus","Dry! Water me!!",60,PUBLIC);//for IFTTT to email me a reminder
    if( dryDay>=3){
        Particle.publish("SoilStatus","Haven't water for three days!!",60,PUBLIC);
        //for IFTTT to create a post on my personal website announcing how I don't take care of my plant for 3 days
    	last_published = millis();
        	digitalWrite(ledPin, 200);
    shouldLedOn=true;//turn on the LED
   // delay(5000);

 else if (sensorValue <= thresholdDown){//too much water for the plant
	if( last_published + 60000 < millis() ){
    Particle.publish("SoilStatus", "Too much water!",60,PUBLIC);
    last_published = millis();
    dryDay=0;        	}
        	 digitalWrite(ledPin, 0);
  shouldLedOn=false;//turn off the LED


  else {//enough water for the plant

   // digitalWrite(LEDs, LOW);
	if( last_published + 60000 < millis() ){
    Particle.publish("SoilStatus", "No Water Needed!",60, PUBLIC);
     last_published = millis();
        	 digitalWrite(ledPin, 0);



void readTheSensor() {
    val = digitalRead(inputPin);

bool calibrated() {
    return millis() - calibrateTime > 0;

void setLED(int state) {

void reportTheData() {
    // for the piezo to playNotes based on the PIR sensor feedback(when the plant needs water, play notes when someone appraoch)
    if (val == HIGH) {
        // the current state is no motion
        // i.e. it's just changed
        // announce this change by publishing an event
        if (pirState == LOW) {
          // we have just turned on
          Particle.publish("PhotonMotion", "Motion Detected", PRIVATE);
          // Update the current state
          pirState = HIGH;
    } else {
        if (pirState == HIGH) {
          // we have just turned of
          // Update the current state
          Particle.publish("PhotonMotion", "Off", PRIVATE);
          pirState = LOW;


void playNotes()
    // iterate over the notes of the melody:
    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 noteDuration = 1000/noteDurations[thisNote];
      tone(speakerPin, melody[thisNote],noteDuration);

      // to distinguish the notes, set a minimum time between them.
      // the note's duration + 30% seems to work well:
      int pauseBetweenNotes = noteDuration * 1.30;
      // stop the tone playing:
Click to Expand

Circuit diagram  


Next Steps

To achieve a more consistent interaction for the device instead of separating different functions and also consider how its functions and structure can better work with its possible forms.

Also, the prototype for now still has a learning curve for the user, so the signals should be more intuitive in communicating information.

For the optimization part, I would try to increase the variety and granularity of the data collected to get a more detailed condition of the plant in order to design more responsive feedback. (e.g. different approaches for different moisture levels)



Considering how I addressed the challenges and my original expectations, I think I get where I wanted to, yet the project still needs a lot of improvements in terms of how to better interact with the user. It needs to be more exquisite in form, sensitivity, and maybe also in communication to achieve a satisfying experience.

Share this Project


49713 Designing for the Internet of Things

· 16 members

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


Combine multiple, progressive layers of reminder for plant watering, from ambient display all the way to breaking into your working environment


November 7th, 2019