How to NOT become a plant murder 101

Using the Internet of Things to create a smart plant

Avantika Chaturvedi
9 min readFeb 16, 2021
Photo by Thomas Verbruggen on Unsplash

How absent-minded do you have to be to kill a cactus?

I mean those things require water around once a week and literally live in deserts. I guess to answer the question, I would say you have to be as absent-minded as me. Unfortunately, my cactus died just last month 😔. Really Avantika? You managed to kill a cactus? I know, I know, it doesn’t sound nice, but these days who has time to remember these things? We’re all so busy with our lives that it’s easy to forget about simple things like watering our plants. But, I decided it was about time that my plants start living longer than 1 week, and to do that, I had to turn my plants into smart plants.

STEP 1: The Hardware

By smart plant, I mean that we will now be able to know when our plants need to be watered, monitor their conditions, and be able to turn on artificial lighting for plants if they aren’t receiving enough light. But to be able to start off, I needed the necessary hardware.

Hardware I used (All available on Amazon or by getting the Oplà IoT kit by Arduino):

  • Arduino MKR WiFi 1010
  • MKR IoT Carrier
  • Micro USB cable
  • Moisture sensor

(OPTIONAL: If you want to make this project more portable and compact, you can place the MKR IoT Carrier in a plastic casing)

To learn how to set up the hardware like this click here

Breakdown of the sensors and components

One of the best parts of our MKR IoT Carrier is that it comes with so many embedded sensors and LEDs, removing the need to purchase any external ones. For this project we will only be using 2 sensors from it and the LED’s.

LED Lights: The RGB LEDs on the carrier are used to create artificial light in this project. This is a good feature if we don’t have access to sunlight because we can simply aim the carrier towards the plant and provide the light it needs.

Temperature sensor: The HTS221 sensor on our carrier, simply records the temperature and humidity. We can read its values on the cloud, or we can create conditionals in the code for them.

Light sensor: The APDS9960 ambient light sensor also comes with the MKR IoT Carrier. It is not designed to measure UV light, so it does not precisely read the sun. But, it can measure the intensity of light, so we get a good idea of whether the plant is exposed to any sunlight or artificial light.

The MKR Carrier that includes our sensors, LED’s, as-well as a display screen. Source

Moisture sensor: This is the most important sensor we need to make our smart plant, and one of the most powerful sensors. It has two exposed conductors and is basically a variable resistor. When it’s exposed to water, the resistance drops as the conductivity is increased, while less water means higher resistance. When we place this sensor into a plant pot that was watered recently, the resistance value will be low (eg. 20), but when it has been dried up its resistance level will be high (eg. 1000).

How the moisture sensor works (source)

After we have all our hardware setup and connected to our wire, it’s time to start coding!

*IMPORTANT*

Before the code, you must make sure that you have configured your IoT cloud.

To do that, we will begin by navigating to the Arduino IoT cloud by clicking the button from the menu in the top right corner of their website.

Once we are in, let’s create a new thing. Then, we need to choose the board that we want to associate this new thing with by clicking on the Select Device button in the Device section. If we have configured a board previously, it will appear here, but we can also click on Set up a new device if we want to configure a new device. If you have not yet set up your MKR WiFi 1010 board in the cloud, you can click here for further instructions.

Note: We can only have one device linked to one thing at the same time. If we select a device that is linked to another thing, it will not be linked to that thing anymore.

We will also need to make sure that we enter the credentials on our network. This is done by clicking on the Configure button in the network section.

Note: If we have not linked a device to the thing, the configure button cannot be clicked.

When we have created our thing, we will also need to create seven variables, following the table below:

Note: waterpump and cooling_fan are optional variables

The interaction column refers to the switch inside the variable configuration, next to the text “Modify from dashboard and API”. If it is ON, it means we can interact with it in the dashboard; if it is OFF, we can only monitor. Once we have created the variables, we can go to the sketch tab and start completing the code.

STEP 2: The Code

All the code I have done was on Arduino’s Web Editor. After making an Arduino account you can access the web editor here.

The first thing we have to do in our code is to initialize this program, which begins with including “thingProperties.h” and <Arduino_MKRIoTCarrier.h>. We will also assign a moistPin variable to pin A5, which will be used to read values from the moisture sensor. Now, we will also create three strings, waterPumpState, coolingFanState, and lightState, which will later be used to store the states of our RGB LEDs.

Then, we will create two 32-byte integers called lightsOn and lightsOff. These store the colour codes that we will use to turn the lights on or off.

#include "thingProperties.h"
#include <Arduino_MKRIoTCarrier.h>
MKRIoTCarrier carrier;

int moistPin = A5;
String waterPumpState;
String coolingFanState;
String lightState;

uint32_t lightsOn = carrier.leds.Color(82, 118, 115);
uint32_t lightsOff = carrier.leds.Color(0, 0, 0);

Now undersetup() , we are going to write the command while(!Serial); which stops the program from running until we open the serial monitor, and we will also write carrier.begin(); that initializes the carrier library. We also set the CARRIER_CASE boolean to false. But, if you want to use the plastic encasing like I did, we need to set this variable to true.

(Some of the extra code that you see below is automatically there when you create a new project.)

void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);

// Defined in thingProperties.h
initProperties();

// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
//Get Cloud Info/errors , 0 (only errors) up to 4
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();

//Wait to get cloud connection to init the carrier
while (ArduinoCloud.connected() != 1) {
ArduinoCloud.update();
delay(500);
}

delay(500);
CARRIER_CASE = true;
carrier.begin();
carrier.display.setRotation(0);
delay(1500);
}

Then, in the loop() program of our code, we will read the temperature, humidity, light and raw moisture values. We are mapping the moisture value from the range 0–1023 and 100–0, so it becomes easier for us to understand (ie. it lets us read the moisture levels like 75% or 10%, as opposed to 1029).

void loop() {
//Update the Cloud
ArduinoCloud.update();

//read temperature and humidity
temperature = carrier.Env.readTemperature();
humidity = carrier.Env.readHumidity();

//read raw moisture value
int raw_moisture = analogRead(moistPin);

//map raw moisture to a scale of 0 - 100
moisture = map(raw_moisture, 0, 1023, 100, 0);

//read ambient light
while (!carrier.Light.colorAvailable()) {
delay(5);
}
int none; //We dont need RGB colors
carrier.Light.readColor(none, none, none, light);

delay(100);

}

Then we will write our functions that were tied to the boolean variable. The main function that we have is the onArtificialLightChange() function where we will control the RGB LEDs to produce artificial light for our plant. Now I have also included 2 other functions that our optional to put in, which are our onCoolingFanChange() function, where you could link a fan and it could cool down our plant if necessary, and the onWaterpumpChange() function where you could attach a water pump that would automatically pump water when needed. (I do not have a water pump or cooling fan, but in the future if I have one, I can now easily link it)

void onWaterpumpChange() {
if (waterpump == true) {
carrier.Relay2.open();
waterPumpState = "PUMP: ON";
} else {
carrier.Relay2.close();
waterPumpState = "PUMP: OFF";
}
updateScreen();
}

void onCoolingFanChange() {
if (cooling_fan == true) {
carrier.Relay1.open();
coolingFanState = "FAN: ON";
} else {
carrier.Relay1.close();
coolingFanState = "FAN: OFF";
}
updateScreen();
}

void onArtificialLightChange() {
if (artificial_light == true) {
carrier.leds.fill(lightsOn, 0, 5);
carrier.leds.show();
lightState = "LIGHTS: ON";
} else {
carrier.leds.fill(lightsOff, 0, 5);
carrier.leds.show();
lightState = "LIGHTS: OFF";
}
updateScreen();
}

The updateScreen() function is called from all the previous functions, which is used to update the display screen on the MKR IoT Carrier each time a state has changed. Three states can be updated:

  • waterPumpState - tells whether the "pump" is on or off.
  • coolingFanState - tells whether the "fan" is on or off.
  • lightState - tells whether the "light" is on or off.
//Update displayed Info
void updateScreen() {
carrier.display.fillScreen(ST77XX_BLACK);
carrier.display.setTextColor(ST77XX_WHITE);
carrier.display.setTextSize(3);

carrier.display.setCursor(40, 50);
carrier.display.print(waterPumpState);
carrier.display.setCursor(40, 90);
carrier.display.print(coolingFanState);
carrier.display.setCursor(40, 130);
carrier.display.print(lightState);
}

Full code available here.

STEP 3: The Data

Currently, when you run your code you’ll notice that nothing is really happening. This is because we still have a really important step left! We now have to visualize our data. To do this, we can navigate to the Dashboards tab. Here we need to create a new dashboard by clicking the Build Dashboard button, which will open a new window with an empty dashboard. Once we have a new dashboard, we will need to create seven widgets that we will link to the variables that we created earlier when we configured our IoT cloud. We can follow the table below to create these widgets:

After creating all of these widgets, your dashboard should look something like the image below, and you should now be able to monitor your plants!

Our final setup!

STEP 4: Get notified (Optional)

Being able to monitor my plant wasn’t enough for me though, because that wouldn’t help me to remember when to water it. The only way I would remember, is if I was notified. I decided to use Zappier, to send daily updates on my plant’s health and conditions through Gmail, and get a warning if the plant moisture or light levels were too low.

The email that is sent to me daily

To see how to connect your IoT system to Zappier, follow this simple tutorial!

And that’s it! You just turned your plant, into a smart plant.

Check out my youtube video to see a live demo:

Let’s Connect!

Feel free to contact me at avantikachat@gmail.com, or connect with me on my Linkedin. If you would like to receive monthly updates about what I’ve been up to and my future articles subscribe to my newsletter here!

If you liked the is article be sure to check out the one I wrote explaining IoT on a deeper level here.

--

--