This workshop was designed by POWAR STEAM for the Maker Faire in Lisbon 2022, and it is inspired and sponsored by Seeed Studio and their WIO Terminal. An IoT device that has helped empower our POWAR climate simulator and given us a lot of new ideas about its uses in education.
Here is the documentation we used to give the workshop, and you can feel free to use it and replicate it to give more workshops
Introduction - Smart Garden using Seeed Studio WIO terminal (gitbook.io)
Additional to the original tutorial that Seeed Studio created for this project, I also designed a 3D Printed case for sticking the WIO terminal to the plant and modified a design of a moisture sensor case that could be useful. I will upload the files at the end of the documentation in case you want to print them.
The Wio Terminal is a SAMD51-based microcontroller with Wireless Connectivity powered by Realtek RTL8720DN that’s compatible with Arduino and MicroPython. Currently, wireless connectivity is only supported by Arduino. It runs at 120MHz (Boost up to 200MHz), 4MB External Flash and 192KB RAM. It supports both Bluetooth and Wi-Fi providing the backbone for IoT projects. The Wio Terminal itself is equipped with a 2.4” LCD Screen, onboard IMU(LIS3DHTR), Microphone, Buzzer, microSD card slot, Light sensor, and Infrared Emitter(IR 940nm). On top of that, it also has two multifunctional Grove ports for Grove Ecosystem and 40 Raspberry pi compatible pin GPIO for more add-ons.
Seeed studio has a great Wiki about the WIO Terminal where you can find different codes, instructions and tutorials to use it. Here you can find all the information about the WIO terminal on the Seeed Wiki.
You can either buy the components separately or as a kit. Here is the link to get the WIO terminal or other WIO kit of your interest. The page on the Seeed Studio bazar to buy it.
Seeed Studio already sells a kit to do this project, so you could buy everything together. The Smart Garden project Kit
This is the tutorial that inspired this project:2 - Smart garden systems:A Smart Garden is a gardening system that uses technology to automate various aspects of plant care. It includes sensors, software, and other devices to monitor soil moisture, light, temperature, and other factors influencing plant growth.
The information collected by these devices is used to control irrigation, fertilization, and other aspects of plant care, with the goal of making gardening more efficient and effective. The aim is to provide ideal growing conditions for plants and optimize their growth while reducing the need for manual labour and guesswork.
3.1 - Planning steps:To plan our smart garden system, we must consider some of the following things:
- The type of measurements we want to obtain to know what sensors we want to use.
- The actions do we want to perform with our system such as activating a water pump? turning on a light? a heating or cooling system? an alarm sound? etc.
- What information do we want to transmit and how? since it could be on an integrated screen, in the serial monitor, on an external screen, in an application, a database or an internet dashboard.
- The number of plants we will control to know the number of necessary components.
- Where will our system be located to decide if we need to place it in a specific compartment or what will be its source of energy?
In this specific case, we are going to build a system that gets the environmental temperature, relative humidity, light intensity and soil moisture.
We won't actuate with any external component at the moment, but we will activate the internal buzzer if the soil moisture of the plant is too low, accompanied by a visual notification on the screen.
We will display on the WIO terminal screen the values from our four sensors: Temperature, humidity, soil moisture and light. And also program the on-screen notification for low soil moisture. In the future, we could connect this device to the internet and publish the data on an App or digital dashboard.
We will only control one plant, in interior conditions and powered by the USB-C cable at the moment.
4 - Connect the sensors:The WIO terminal includes two grove ports to connect our sensors, and also 40 GPIO pins like the raspberry where you could connect a lot more things. The good thing is that when working with the WIO terminal and the Grove Sensors, these sensors are "plug and play", meaning that you won't have to bother for connections, but instead just plug them, code and use them.
For our Smart Garden System, we are going to use just the integrated ports, but we need to consider that the LSFT port is an I2C port that later on we can also use as a Digital/Analogue pin, and the RIGHT port is connected to the D0/A0 and D1/A1.
*So for the initial testing of our sensors and our code we are just going to use the RIGHT port. and then we are going to turn the I2C port into an analogue/digital port so we can use both sensors.
This would be the way to connect pour sensors to both ports, but for that, we need to declare the I2C (LEFT) port in our code to work not as an I2C with the next instruction:
#define DHTPIN PIN_WIRE_SCL
The Light sensor and the buzzer are integrated into the WIO, so those two won't need any connection. We will just need to declare them with the proper instructions according to the WIO Library which are WIO_LIGHT and WIO_BUZZER:
pinMode(WIO_LIGHT, INPUT);
pinMode(WIO_BUZZER, OUTPUT);
For this specific project, you will need to install the Arduino IDE software in order to code the WIO Terminal, the DHT library to read the DHT11 sensors, and the LCD screen library.
5.1 - Arduino IDETo install the Arduino IDE click on the link below to open the web page with the installer.
DOWNLOAD LINK: Software | Arduino
- Select the version of Arduino IDE based on the operating system of your computer.
- Decide if you want to donate, or click on "Just Download"
- After downloading the installer, execute it and follow the instructions.
- Open your Arduino IDE, click on File -> Preferences, and copy the URL below to Additional Boards Manager URLs:
https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
- Click OK
- Click on Tools -> Board -> Board Manager and Search Wio Terminal in the Boards Manager.
- Connect your WIO Terminal to the computer
- On the Arduino IDE click on Files ->Examples ->01. Basics > Blink (this will open a sample code that will make the WIO Terminal internal LED Blink every second).
- Click on Tools -> Board -> Board Manager and Search Wio Terminal in the Boards Manager.
- Select the serial device of the Wio Terminal board from the Tools -> Port menu.
- Now, simply click the Upload button in the environment. Wait a few seconds and if the upload is successful, the message "Done uploading." will appear in the status bar.
- Upload the code
- Now the Blue led at the bottom of your WIO Terminal should be blinking every second.
- Visit the Seeed DHT library Github repositories and download the entire repo to your local drive.
- Go to the library link, click the green
CODE
button, and selectDownload as Zip
- Open the Arduino IDE, click
sketch
->Include Library
->Add .ZIP Library
, and choose theGrove_Temperature_And_Humidity_Sensor-master
file that you have just downloaded.
- Visit the Seeed_Arduino_LCD Github repositories and download the entire repo to your local drive.
- Open the Arduino IDE, click
sketch
->Include Library
->Add .ZIP Library
, and choose theSeeed_Arduino_LCD
file that you have just downloaded.
Some functions of the TFT LCD Library require this library.
- Navigate to
sketch
->Include Library
->Manager Library
, and a library manager window will appear. - Search Adafruit Zero DMA and click Install.
In order to properly debug each part of the project, it is important to test the codes evolutionarily, testing the code of each sensor or action independently and then the code of the entire project as a whole. This way we will know what is working and what is not.
All the codes are uploaded at the end of the documentation, but I will add them again in he separately.
6.1 - WIO Internal Light sensor:This code will let you read the WIO Terminal Integrated Light Sensor and show the results in the serial port of your computer.
void setup() {
// put your setup code here, to run once:
// declare PinMode
pinMode(WIO_LIGHT, INPUT);
//Start serial communication
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
// declare a variable to store the read values
int light = analogRead(WIO_LIGHT);
// print in the serial monitor the sensor values
Serial.print("Light Value: ");
Serial.println(light);
// wait 1 second to read again
delay(1000);
}
6.2 - WIO Internal BuzzerThis code will let you actuate the WIO Terminal Integrated Buzzer, beeping for one second and stopping for another second.
void setup() {
pinMode(WIO_BUZZER, OUTPUT);
}
void loop() {
analogWrite(WIO_BUZZER, 128);
delay(1000);
analogWrite(WIO_BUZZER, 0);
delay(1000);
}
6.3 - WIO Light to BuzzWe are going to use the light sensor to activate the buzzer depending on the amount of light it gets, as an example of how we can mix codes.
void setup() {
// put your setup code here, to run once:
// declare PinMode
pinMode(WIO_LIGHT, INPUT);
pinMode(WIO_BUZZER, OUTPUT);
//Start serial communication
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
// declare a variable to store the read values
int light = analogRead(WIO_LIGHT);
// print in the serial monitor the sensor values
Serial.print("Light Value: ");
Serial.println(light);
if (light > 200) {
analogWrite(WIO_BUZZER, 100);
Serial.println("SUNNY");
}
else
{
analogWrite(WIO_BUZZER, 0);
Serial.println("DARK");
}
// wait 1 second to read again
delay(500);
}
6.4 - Grove DHT11 readThis code will let you read the Grove DHT11 with the WIO Terminal and show the results in the serial port of your computer, giving us the actual temperature in ºC and the Relative Humidity %.
#include "DHT.h" //DHT library
#define DHTPIN D0 // define the digital pin 0
#define DHTTYPE DHT11 //Define the DHT sensor type
DHT dht(DHTPIN, DHTTYPE); // initialize DHT sensor
void setup() {
// put your setup code here, to run once:
//Start serial communication
Serial.begin(9600);
//Start DHT sensor
dht.begin();
}
void loop() {
// put your main code here, to run repeatedly:
//create an integer T to store the Temperature value
int t = dht.readTemperature();
//create an integer H to store the Humidity value
int h = dht.readHumidity();
// Print Temperature and Humidity Values
Serial.print("Temperature: ");
Serial.print(t);
Serial.println("ºC");
Serial.print("Humidity: ");
Serial.print(h);
Serial.println("%");
delay(2000);
}
6.5 - Grove Soil Moisture readThis code will let you read the Grove Soil Moisture Sensor with the WIO Terminal and show the results in the serial port of your computer. The values will change according to the level of humidity or dryness on the sensor.
// declare to which Pin the sensor is connected
int sensorPin = A0;
// declare the initial value of the sensor
int sensorValue = 0;
void setup() {
// open the serial port (the communication with the computer to show values)
Serial.begin(9600);
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
// print the value in the serial monitor
Serial.print("Moisture = " );
Serial.println(sensorValue);
// wait one second to start again
delay(1000);
}
6.5.3 - Grove Soil Moisture value Mapping to percentageIn order to achieve more understandable values, we will map the soil moisture sensor so that it gives percentage values. For this, we must first calibrate it to understand what are the values that the sensor reading throws when it is totally dry, when it is submerged in water and when it is in wet soil.
So the first thing to do will be to test our soil sensor in dry conditions and annotate the value, then on totally wet conditions by submerging it into a cup with water, and then the values for wet soil. This last value will also depend on what we consider the correct wetness of the soil for the plant that we want to take care of.
6.5.2 - Grove Soil Moisture MapIn the next code, we should change the first two values in the mapping function for the values we got from our calibration exercise:
// map the values (TOTALLY WET_reading, TOTALLY DRY_reading, 100%, 0%)
sensorValue = map(sensorValue, 1023, 0, 100, 0);
So you should change the 1030 value for the value of your sensor soaked in water, and the 0 for the value when it is dry... this dry value usually is between 0 and 3, so 0 might work well.
// declare to which Pin the sensor is connected
int sensorPin = A0;
// declare the initial value of the sensor
int sensorValue = 0;
void setup() {
// open the serial port (the communication with the computer to show values)
Serial.begin(9600);
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
// map the values (HIGHEST_reading, LOWEST_reading, 100%, 0%)
sensorValue = map(sensorValue, 1023, 0, 100, 0);
// print the value in the serial monitor
Serial.print("Moisture = " );
Serial.print(sensorValue);
Serial.println(" %" );
// wait one second to start again
delay(1000);
}
6.5.2 - Grove Soil Moisture assigning functions to values:This code will assign some functions to the values, so that it acts differently depending if the soil is dry, in a good wet state or too wet. In this case, the sensor will send different messages to the serial monitor.
// declare to which Pin the sensor is connected
int sensorPin = A0;
// declare the initial value of the sensor
int sensorValue = 0;
void setup() {
// open the serial port (the communication with the computer to show values)
Serial.begin(9600);
}
void loop() {
// read the value from the sensor:
sensorValue = analogRead(sensorPin);
// map the values (HIGHEST_reading, LOWEST_reading, 100%, 0%)
sensorValue = map(sensorValue, 1023, 0, 100, 0);
/* a conditional that tells us that the plant is DRY
if the value is LESS or equal to 300 */
if (sensorValue <= 30) {
Serial.println("DRY SOIL...PLANT NEEDS WHATER" );
Serial.print("Moisture = " );
Serial.print(sensorValue);
Serial.println(" %" );
}
/* a conditional that tells us that the plant is TOO WET
if the value is MORE or equal to 700 */
if (sensorValue >= 70) {
Serial.println("SUPER WET...TOO MUCH WATER" );
Serial.print("Moisture = " );
Serial.print(sensorValue);
Serial.println(" %" );
}
/* a conditional that tells us that the plant is HAPPY
if the value is LESS than 700 and MORE than 300 */
if (sensorValue < 70 && sensorValue > 30) {
Serial.println("PERFECT MOISTURE...PLANT IS HAPPY" );
Serial.print("Moisture = " );
Serial.print(sensorValue);
Serial.println(" %" );
}
// a space between the writing of the readings
Serial.println();
// wait one second to start again
delay(1000);
}
6.6.1 - Screen display text on a colour background:This code will load the needed library to use the screen and will set the background colour and rotation, font size and colour, and display text on the desired location of the screen.
#include "TFT_eSPI.h"
TFT_eSPI tft;
void setup() {
tft.begin();
tft.setRotation(3);
tft.fillScreen(TFT_GREEN);
tft.setTextSize(4);
tft.setTextColor(TFT_WHITE);
tft.drawString("POWAR GARDEN", 20, 100);
}
void loop() {
}
6.6.2 - Light Sensor + LCD:This code will read the light sensor value, and display its information on the LCD screen. This will show you how the basic integration of codes we have tried works on the LCD.
#include "TFT_eSPI.h"
TFT_eSPI tft;
void setup() {
tft.begin();
tft.setRotation(3);
tft.fillScreen(TFT_GREEN);
}
void loop() {
int lightVal = analogRead(WIO_LIGHT);
tft.fillScreen(TFT_GREEN);
tft.setCursor(tft.width() / 2, tft.height() / 2);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(4);
tft.println(lightVal);
delay(50);
}
7 - Full Code using DHT11:This code will initialize by loading the libraries, then set the PinModes for the internal LIGH sensor and BUZZER as Inputs and Outputs, then start the DHT sensor, start the screen and set the initial rotation and size, and draw an initial welcome message.
Then, in the VoidLoop, it will fill the screen with White, draw a Green rectangle on top, draw some vertical and horizontal lines, and then read and map each of the sensors and display their values.
At the end of the code, we added a conditional so that if the Soil sensor reading is too low (DRY) it will display a message on the screen and start beeping.
You should also consider modifying this code with the calibration values you've got from the previous calibration exercise.
#include "TFT_eSPI.h"
#include "DHT.h"
// Set the I2C pin into a Digital/Analogue Pin
#define DHTPIN PIN_WIRE_SCL
// Define the kind of DHT sensor you use
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
TFT_eSPI tft;
TFT_eSprite spr = TFT_eSprite(&tft);
int moisturePin = A0;
int moistureVal = 0;
void setup() {
// declare the pinModes of the internal LIGH sensor and BUZZER
pinMode(WIO_LIGHT, INPUT);
pinMode(WIO_BUZZER, OUTPUT);
// Begin DHT sensor and Screen
dht.begin();
tft.begin();
// Set initial screen parameters
tft.setRotation(3);
spr.createSprite(TFT_HEIGHT, TFT_WIDTH);
// Draw the initial Screen
tft.fillScreen(TFT_GREEN);
tft.setTextSize(4);
tft.setTextColor(TFT_WHITE);
tft.drawString("POWAR GARDEN", 20, 100);
tft.setTextSize(2);
tft.drawString("With Seeed Studio", 60, 180);
// Beep once when it starts
analogWrite(WIO_BUZZER, 150);
delay(100);
analogWrite(WIO_BUZZER, 0);
delay(2000);
// Draw the Maker Faire Screen
tft.fillScreen(TFT_BLUE);
tft.setTextSize(3);
tft.setTextColor(TFT_RED);
tft.fillRect(20, 20, 280, 200, TFT_WHITE);
tft.drawString("Maker Faire", 65, 90);
tft.setTextColor(TFT_BLUE);
tft.drawString("LISBON", 110, 130);
delay(1500);
}
void loop() {
// Declare the initial Variables for the code and MAP the Values
int t = dht.readTemperature();
int h = dht.readHumidity();
// This code will MAP the SOIL MOISTURE values
mnoistureVal = analogRead(mnoisturePin);
mnoistureVal = map(mnoistureVal, 1023, 0, 100, 0);
// This code will MAP the LIGH SENSOR values
int light = analogRead(WIO_LIGHT);
light = map(light, 0, 1023, 0, 100);
// This will set the screen to White and draw a DarkGreen rectangle on top
spr.fillSprite(TFT_WHITE);
spr.fillRect(0, 0, 320, 50, TFT_DARKGREEN);
spr.setTextSize(3);
spr.setTextColor(TFT_WHITE);
spr.drawString("POWAR GARDEN", 55, 15);
// This will draw vertical and horizontal lines to divide the screen
spr.drawFastVLine(150, 50, 190, TFT_DARKGREEN);
spr.drawFastHLine(0, 140, 320, TFT_DARKGREEN);
// Draw TEMPERATURE Value
spr.setTextColor(TFT_BLACK);
spr.setTextSize(2);
spr.drawString("Temperature", 10, 65);
spr.setTextSize(3);
spr.drawNumber(t, 50, 95);
spr.drawString("C", 90, 95);
// Draw HIMIDITY Value
spr.setTextSize(2);
spr.drawString("Humidity", 25, 160);
spr.setTextSize(3);
spr.drawNumber(h, 30, 190);
spr.drawString("%RH", 70, 190);
// Draw SOIL MOISTURE Value
spr.setTextSize(2);
spr.drawString("Soil Moisture", 160, 65);
spr.setTextSize(3);
spr.drawNumber(mnoistureVal, 200, 95);
spr.drawString("%", 240, 95);
// Draw LIGHT Value
spr.setTextSize(2);
spr.drawString("Light", 200, 160);
spr.setTextSize(3);
spr.drawNumber(light, 205, 190);
spr.drawString("%", 245, 190);
// This is the conditionals for the soil moisture alarm
if (sensorVal < 40) {
spr.fillSprite(TFT_DARKGREEN);
spr.setTextColor(TFT_WHITE);
spr.drawString("SAD PLANT", 80, 100);
analogWrite(WIO_BUZZER, 0);
spr.pushSprite(0, 0);
delay(1000);
spr.fillSprite(TFT_RED);
spr.setTextColor(TFT_YELLOW);
spr.drawString("TIME TO WATER!", 40, 100);
analogWrite(WIO_BUZZER, 150);
spr.pushSprite(0, 0);
delay(1000);
analogWrite(WIO_BUZZER, 0);
}
spr.pushSprite(0, 0);
delay(50);
}
8 - 3D printed casesAfter you have your code working, your sensors calibrated and properly connected and the screen displaying the information, you can jump into printing this case I designed for the system, or a case for the Grove moisture sensor I modified the v1.0 by ChinoCamposg on Thingiverse: https://www.thingiverse.com/thing:4163229 I uploaded both files to the documentation!
Hope you have fun with this project, and please write to me if you have any comments.
Comments
Please log in or sign up to comment.