IoT: Plant Buddy

For absolute beginners or anyone interested in implementing IoT with sensors.

Laibah Ahmed
The Innostation Publication

--

A new plant store opened up next to my house and they’ve been rightfully taking every dollar of my allowance. That means that I’ve been posed with another issue in life, and no, it’s not the lack of money in my wallet at the moment. It's that all of the plants need to be watered at different intervals and I keep forgetting when I’ve watered which one, or how much water is in the soil of a plant currently since there are so many different plants of different sizes.

P.S, there's way more. These are just the ones that fit on this table.

I suddenly feel quite sympathetic for early farmers and people who tend to even more crops at a time, but I found out that tech can actually solve this issue. Farmers can use soil moisture sensors enabled with IoT to see how moist certain parts of soil are and then have that information trigger an action like a recorded update or auto watering!

But, I’m unfortunately not a farmer nor have the conditions in my small New York apartment to have a fully automated watering system, but I can make a soil moisture sensor that is enabled with IoT.

This project tutorial goes step by step into building a ‘plant buddy’ that collects data through a SparkFun Soil Moisture Sensor and then relays the information into a formatted google sheet. The data then gets reformatted and transferred to the ios reminders app. This way, you have the logged data history with timings on the google sheet and have the reminders on your phone that can be dismissed once registered and taken care of.

This project can easily be tweaked to work even without your Arduino plugged into a computer, and by sending information through wifi. No prior knowledge of how to code, use Arduinos, implement IoT, or anything in this field is necessary. To know more about what IoT is I suggest reading this article first.

What you’re going to need to buy or supply:

1x Arduino MKR1000 Wifi with Headers

1x SparkFun Soil Moisture Sensor

Jumper Wires

USB connector wire (Any micro USB cable works too, I just used a Kindle charger.)

Optional: 1x Breadboard

Optional: A power bank or 3.3v battery to make this project wireless. This project works perfectly fine plugged into a computer or power source, however, it also works wirelessly with an alternative power source as it was created to do so. I personally keep it plugged in so I can tweak my code however I want and upload it instantly, but I recommend that the final outcome is wireless for ease of use.

Before we dive into it, I highly recommend keeping a doc or somewhere you are able to take digital notes open on another tab open to write down long strings of information and other data/code we need to move from place to place.

I’m going to be splitting this tutorial into two parts just so that we can get it over with and be more familiar with some things before we get into the harder stuff.

Part 1: The Easy Stuff

First, we’re going to get the hardware out of the way.

We need three jumper wires, the sensor, and the Arduino. You can use a breadboard here to keep things secure and steady but it’s not necessary for the functionality of this project.

Your sensor has three holes corresponding to these three inputs. VCC is another term for 3.3v, the voltage that we are working with. It is how much power the sensor and Arduino would be using. The MKR1000 can work with both 3.3v and 5v. Next is GND, This means ground, it’s where the electricity goes away safely. Lastly, we have SIG, which is for the soil moisture reading. We just connect it to an analog pin on our Arduino so that collected data goes through somewhere specific that we can target and use. We connect these points with jumper cables to the corresponding areas on the Arduino, for the SIG I use A1, its the one I select with my code as well.

Part 2: The Harder Stuff

I’m going to go through multiple steps here, so here's a mini table of contents to help you get the gist of what's going to happen.

  1. Preparing the google sheets + code
  2. Incorporating the API PushingBox.
  3. Setting up Arduino (if you haven’t already) + code
  4. Configuring for ios Reminders with IFTTT

Preparing the google sheets + code

Our information is going to be sent and recorded on google sheets.

  1. Open a new Google Sheet using your Gmail. Name the Google Sheet whatever you want and then get ready to save a long string of characters. So where the URL of the Google Sheet is you’re going to see a /d/ followed by a bunch of random letters and numbers, and then /edit. This is called the URL Key to your spreadsheet. Copy and paste that somewhere for use later.

2. Now we’re going to add some code to this sheet. To do so we need to open Google Script, also known as Gscript. Extensions > Apps Script.

Once there, name the Gscript and delete the starter code on there.

Copy and paste this code into the Gscript editor.

function doGet(e) { 
Logger.log( JSON.stringify(e) ); // view parameters

var result = 'Ok'; // assume success

if (e.parameter == undefined) {
result = 'No Parameters';
}
else {
var id = 'YOUR_SPREADSHEET_URL_HERE';//docs.google.com/spreadsheetURL/d
var sheet = SpreadsheetApp.openById(id).getActiveSheet();
var newRow = sheet.getLastRow() + 1;
var rowData = [];
//var waktu = new Date();
rowData[0] = new Date(); // Timestamp in column A

for (var param in e.parameter) {
Logger.log('In for loop, param='+param);
var value = stripQuotes(e.parameter[param]);
//Logger.log(param + ':' + e.parameter[param]);
switch (param) {
case 'moistureHum': //Parameter
rowData[1] = value; //Value in column B
break;
default:
result = "unsupported parameter";
}
}
Logger.log(JSON.stringify(rowData));

// Write new row below
var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
newRange.setValues([rowData]);
}

// Return result of operation
return ContentService.createTextOutput(result);
}

/**
* Remove leading and trailing single or double quotes
*/
function stripQuotes( value ) {
return value.replace(/^["']|['"]$/g, "");
}
}

Now we only have to add in the URL Key we saved before. Copy and paste that between the single apostrophes where it says:

var id = '   '; // Spreadsheet ID

It should look like this but with your own URL Key.

3. Now that we have the code in place, we have to deploy this. To do so, click deploy on the top right corner. Deploy > New Deployment, from the pop-up tab select the gear icon in the top left corner next to where it says “Select Type”. Gear > Web App. Put any sort of description, for the second box where it says “execute as”, make sure it’s set to you with your email. For the third box where it says “who has access”, set it to anyone even anonymous. From here, click deploy on the bottom right corner.

Make sure to save the Web App URL that just popped up. Copy and paste it somewhere for use later.

Incorporating the API PushingBox

We need something to send the information from the sensor to the google sheet, this would be called an API middleman. We’re going to use PushingBox.

  1. Create a free account with your Gmail.
  2. Click “My Services” > “Add a Service” > “CustomURl”, “Select This Service”
  3. Fill in the name of the configuration with anything you want. In the second box, paste the Web App URL we saved from the gscript. In the third box, choose the GET option.

4. Now we have to program this service. To do so, click on “My Scenarios” from the bar on the top. Name it anything you want then click the add button. Click the “Add an Action” button at the bottom > click the “Add an Action with this Service” for the service we just set. > copy and paste the code below into the box that just popped up. We are using the GET method below for this data.

?moistureHum=$moistureHum$ 

5. Copy and paste the DeviceID somewhere for later use.

6. We’re going to test what we’ve done so far so that we can make sure we haven’t missed anything before we move on. To do so we are going to manually input data into the sheet. Copy and paste this into your browser, but with your DeviceID that we just saved from PushingBox.

http://api.pushingbox.com/pushingbox?devid=(YOUR-DEVID-HERE)&moistureHum=33

Check your google sheet for the update to make sure everything is working. If not, double-check everything else we’ve done in this part so far for errors.

Setting up Arduino (if you haven’t already) + code

Note: If you already know how to use Arduino then just use the code from here.

If you haven’t already, download the Arduino app. We also need to download a library, this is a package that contains information on how to use different premade codes, for example, for our Arduinos wifi module.

  1. Open Arduino, it should open a blue-rimmed tab with some basic code. We need to first choose the board and port that we are going to work with. To choose the board, plug your Arduino into your device with the micro USB wire, any port works but I used the left USB one on my mac. Then, click over tools on the top left corner > board > boards manager > Arduino SAMD Boards > install. This downloads information for a bunch of boards, including the one we need to use. After you download it just close the manager and backtrack, so instead of clicking boards manager again, you hover over the Arduino SAMD Boards > Arduino MKR 1000. I’ve attached pictures to help.

Note: On the bottom right corner of the tab it should say “Arduino MKR1000 on” and then the name of your port. For me, it automatically went to the port that my Arduino was plugged into, so it says “/dev/cu.usbmodem14201”, but for some reason, if it isn’t selecting you can manually choose the port from tools > port > whichever port is showing other than the Bluetooth basic option. If it still isn’t working switch ports and try the port process again.

2. Now we have to code the Arduino. This is the code:

#include <WiFi101.h>const char WEBSITE[] = "api.pushingbox.com"; //pushingbox API server
const String devid = "DEVID HERE"; //device ID on Pushingbox for our Scenario
const char* MY_SSID = "WIFI NAME HERE";
const char* MY_PWD = "WIFI PASSWORD HERE";
int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial)
{
; // wait for serial port to connect. Needed for native USB port only
}
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// don't continue:
while (true);
}
// attempt to connect to Wifi network:
while (status != WL_CONNECTED)
{
Serial.print("Attempting to connect to SSID: ");
Serial.println(MY_SSID);
//Connect to WPA/WPA2 network.Change this line if using open/WEP network
status = WiFi.begin(MY_SSID, MY_PWD);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to wifi");
printWifiStatus();
}void loop() {// Wait between measurements.
delay(10000);
//prefer to use float, but package size or float conversion isnt working
//will revise in future with a string fuction or float conversion function
float moistureHum = analogRead(A1); //this gets data from the analog pin we connect to with our wiring
moistureHum = (1023 - moistureHum) * 100 /1023;
// Check if any reads failed and exit early (to try again).
if (isnan(moistureHum))
{
Serial.println("Failed to read from sensor!");
return;
}
Serial.print("Soil Moisture ");
Serial.print(moistureHum);
Serial.println("\nSending Data to Server...");
// if you get a connection, report back via serial:
WiFiClient client; //Instantiate WiFi object, can scope from here or Globally
//API service using WiFi Client through PushingBox then relayed to Google
if (client.connect(WEBSITE, 80))
{
client.print("GET /pushingbox?devid=" + devid
+ "&moistureHum=" + (String) moistureHum
);
// HTTP 1.1 provides a persistent connection, allowing batched requests
// or pipelined to an output buffer
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(WEBSITE);
client.println("User-Agent: MKR1000/1.0");
//for MKR1000, unlike esp8266, do not close connection
client.println();
Serial.println("\nData Sent");
client.stop();
}
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}

3. We have to customize some parts of the code. Plug them in the code where they're written.

  • Your SSID (your WiFi name)
  • Your WiFi password
  • Your DeviceID from Pushingbox

To make the code run first click the checkmark button on the top left to verify that it works, then while the Arduino is still plugged in click the Upload button. It would ask you to save the file so just save it in any name and anywhere you want.

Now to make everything come together go-to tools > serial monitor. Keep this tab open and running and you should see it updating within here, as long as it updates on the monitor it should also be updating to the google sheet!

Once the code is running and sending data to the google sheets it should look something like this:

The left-hand side tells you the date, the right-hand side tells you the moisture level. Keep in mind, that this sensor collects data in slower intervals than other sensors since it's a set data value (a specific level of moisture in the soil at one time), and that the soil moisture sensor uses less electricity to prevent corrosion. It sends electricity out and back to see how much resistance it runs into, that's how it determines the moisture level.

Configuring for ios Reminders with IFTTT

We’re at the last and easiest step!

  1. Sign up for IFTTT.
  2. Click “create” and click “add” for the first part of the applet.
  3. Search for google sheets and then choose the option for “new row added to spreadsheet”.

4. Link your email to it, and put the URL of the google sheet in where required. Fill up the base connection parts shown to you.

5. For the “then that” part click “add” and search for “ios reminders” and choose that option.

6. Set up the first part like this, and you can either fill out the rest of the options as you want or just let it be.

7. Download the mobile app and allow changes.

Once you use the sensor everything should automatically start updating and your reminders will look like this:

Data of a plant's soil that I had watered a few hours prior to testing. 90 seems to be the base threshold, so 90 is around “normal”.

The End!

We’ve made it! Now I’m going to be able to monitor more plants more accurately, seems like I should buy more plants right?

--

--

Laibah Ahmed
The Innostation Publication

Interested in the causes & effects of ocean acidification. Currently researching the impact of sulfate sludge discharge from the maritime industry.