I put a carnivorous plant on the Internet of Things to save its life, and it did not survive

This article is a text version of my talk, "I put a carnivorous plant on the Internet of Things," which I presented during the DataNatives conference (November 25-26, 2019 in Berlin, Germany).


It was Winter 1998; all the kids at my primary school were playing with a virtual pet simulation game called Tamagotchi. It was sort of like The Sims of the late 90s, but without beautiful graphics and music (it looked good at the time). Also, the interactions were limited. You could only feed and play with the animal. Somehow, that was enough to keep it alive.

The game put us in trouble at school because a player had to interact with it a few times a day, so teachers were not happy with that. Because we could not play so often, fake animals were constantly dying.

In 2019 I did not have a Tamagotchi anymore. To be honest, I did not even know that you can still buy them. Things have changed. Instead of a Tamagotchi, I have plants.

Not everything has changed because all of my plants keep dying just like the Tamagotchi animals. I think it is time to admit that I have a problem because all of my plants are dead.

Dead plants

Look at this one! I hoped that it wasn’t dead. I was thinking that perhaps it was just preparing for the Winter. I was wrong. The Winter has passed, and the plant was still dead.

Venus Flytrap

At some point, I got a new plant. It was the coolest plant I ever had. I even gave it a name - my plant is called Zdzisław.

Zdzisław is a Venus Flytrap. It likes bugs and wants to be a software tester ;)

Things to do

It should be easy to keep such a plant alive. After all, the only thing it needs is sun and water. No, you don’t have to feed them.

Often, I was forgetting about watering the plant, so I tried reminders — many of them. The problem was, I was never nearby the plant when I had seen the reminder on my phone, and there was always something more urgent to do.

Obviously, I concluded that there must be something wrong with plants! I never had such problems with animals. I mean, the real animals.

Real animals can communicate. My parent’s dog makes noise when he wants something. It may not be the most human-friendly way of communicating, but it works.

I had to help Zdzisław communicate with humans!

What did I need?

For that project, I needed a few things. First of all, a little bit of overengineering because there are dozens of methods to water a plant. Most of them don’t require writing any code.

I also needed ignorance towards 10000 years of agriculture history because we, humans, know how to take care of plants. Humans, in general, know how to do it. I, personally, have no idea.

Last but not least, I needed some equipment that I would use for only one project.

Connecting to server

I started by connecting my Arduino to WiFi. Fortunately, there is a great library I could use, so all I needed was five lines of code and around 15 seconds of waiting time.

1
2
3
4
5
6
7
8
#include <WiFiNINA.h>
 
int status = WL_IDLE_STATUS;
 
while ( status != WL_CONNECTED) {
    status = WiFi.begin(ssid, pass);
    delay(5000);
}

To make the project at least a little bit interesting, I wanted to store the measurements “in the cloud.” I quickly coded a small JavaScript REST API and deployed it on a free Heroku instance.

The first problem with sending anything to my API was the fact that REST client libraries for Arduino are not very popular. I found only a few of them, and I decided that I didn’t want to use them.

Those libraries had only a few stars on GitHub and a couple of forks. I did not want to run such an untrusted code on my computer.

The solution was obvious. I implemented my own REST client. Luckily, I needed only one function supporting one HTTP method and one Content-Type, so I connected to the TCP port and started pretending to be a web browser.

1
2
3
4
5
6
7
8
9
10
11
12
13
String request = "POST " + resource + " HTTP/1.1";
 
if (tcpClient.connect(server, port)) {
    tcpClient.println(request);
    tcpClient.println("Host: " + String(server));
    tcpClient.println("User-Agent: curl/7.60.0");
    tcpClient.println("Accept: */*");
    tcpClient.print("Content-Length: ");
    tcpClient.println(content.length());
    tcpClient.println("Content-Type: application/x-www-form-urlencoded");
    tcpClient.println();
    tcpClient.println(content);
}

Using sensors

When I finished working on the client-server connection, I started reading data from my sensors. At that point, I realized that I made a big mistake.

I purchased the cheapest sensors I could find, so all my data looked like this:

I had no idea why it worked like that. At the time when I measured those values, the sensors were lying on my desk, and I wasn’t even touching it.

There were two more problems with those sensors. What was the unit? What was the range of possible values? The manufacturer of the sensors somehow forgot to mention anything about it in the documentation.

Using the water pump

I realized that I didn’t need to know anything about the measurement units. I needed to figure out when I should switch the water pump on.

It was a very disappointing moment of the project because at the beginning I thought that maybe I could use machine learning for that. In the end, I used an if statement with a constant value as the threshold.

1
2
3
4
5
6
7
float SOIL_HUMIDITY_THRESHOLD = 350;
 
if(soilHumidity < SOIL_HUMIDITY_THRESHOLD) {
    start_pump();
} else {
    stop_pump();
}

The last thing was plugging in the water pump. I could not connect it directly to Arduino because the pump needs a higher voltage. I had to connect it using a power relay between Arduino and the pump. As a consequence, Arduino controls only the relay, which works like a light switch.

1
2
3
4
5
#define ENGINE 7
 
void start_pump() {
  digitalWrite(ENGINE, LOW);
}

When everything was connected and worked correctly, I concluded that I could not use that monstrous device. It was too big, even without the water container.

The outcome

It did not matter. It was too late for Zdzisław. The plant was dead, again. I think it may be time for Zdzisław 2.0. This time everything is going to be different! I mean, I will kill a different plant.

Why do I tell a story of a failed project? I do it because I want to show you that if you want to make your own IoT project, the only thing you need is an answer to one question: If this thing could talk, what would it say?

If the plant could talk, would it tell me when I should water it? If a chair could talk, would it let me know that I’m sitting for too long, and it is slowly killing me?

When you know the answer to that question, the only task left to do is making that thing talk.


Remember to share on social media!
If you like this text, please share it on Facebook/Twitter/LinkedIn/Reddit or other social media.

If you watch programming live streams, check out my YouTube channel.
You can also follow me on Twitter: @mikulskibartosz

If you want to hire me, send me a message on LinkedIn or Twitter.


Bartosz Mikulski
Bartosz Mikulski * data/machine learning engineer * conference speaker * co-founder of Software Craftsmanship Poznan & Poznan Scala User Group