Iot Project Smart Garden: Mokxf16@sp - Edu.sg SCHOOL OF COMPUTING (SOC) Singapore Polytechnic
Iot Project Smart Garden: Mokxf16@sp - Edu.sg SCHOOL OF COMPUTING (SOC) Singapore Polytechnic
SMART GARDEN
[email protected]
SCHOOL OF COMPUTING (SOC) Singapore Polytechnic
Smart Garden Internet of Things Project Step-by-step Tutorial
Table of Contents
Section 1 Overview of project ........................................................................................................... 3
A. Tutorials ........................................................................................................................... 3
B. What is the application about? ........................................................................................ 3
C. Summary of the Steps ...................................................................................................... 4
D. Final Setup........................................................................................................................ 4
E. How does the web application look like? ........................................................................ 5
Section 2 Hardware Requirements ................................................................................................... 7
A. Hardware checklist........................................................................................................... 7
Section 3 Setting up the hardware .................................................................................................... 8
A. Connect Arduino to Raspberry Pi .......................................................................................... 8
B. Connect DHT11 Sensor .......................................................................................................... 8
C. Connect LED ........................................................................................................................... 9
D. Connect Soil Moisture Sensor ............................................................................................. 10
E. Connect DC Motor ............................................................................................................... 10
F. Connect i2c LCD.................................................................................................................... 12
G. Completed Fritzing Diagram ................................................................................................ 13
Section 4 Software Setup ................................................................................................................ 14
A. Installing Arduino Library..................................................................................................... 14
B. Installing Packages & Libraries on RPi ................................................................................. 14
C. Prepare folders .................................................................................................................... 15
Section 5.1 Setting Up Amazon Web Service (AWS) account ......................................................... 16
Sign in to the AWS IoT Console ...................................................................................... 16
Create and register your “Thing” ................................................................................... 17
Create Certificates ......................................................................................................... 18
Create a Security Policy for you RPi ............................................................................... 19
Attach Security Policy and Thing to your Cert ............................................................... 21
Save REST API endpoint ................................................................................................. 23
Section 5.2 Setting Up DynamoDB .................................................................................................. 25
Create AWS Role ............................................................................................................ 25
Create a DynamoDB table .............................................................................................. 26
Create rule to publish MQTT message to DB................................................................. 29
Section 5.3 Configure AWS CLI ........................................................................................................ 32
Configure AWS CLI ......................................................................................................... 32
Section 1
Overview of project
A. Tutorials
The tutorial is linked here: https://www.hackster.io/mokxf16/smart-garden-raspberry-pi-arduino-
65c7b7
We will be using an Arduino and a Raspberry Pi to receive data from the sensors and
control the different actuators. The surrounding temperature, air humidity and brightness
values will be recorded, as well as the soil moisture levels. These values will then be
displayed on the LCD screen, which allow users to know the environmental conditions of the
plants when they check on them.
When the soil moisture level goes above 500 (for our soil moisture sensor, the higher it is
the drier the soil), the red LED will light up as a warning to show that the plant needs water.
Also the water pump will start to run and pump water into the soil automatically. This is very
convenient for users as they do not need to water their plants every time but instead let the
system water their plants automatically based on the moisture level of the soil.
As for the automated light, when the LDR records a value higher than 300, the yellow LED
will light up and act like the sun, to allow continuous photosynthesis to occur for the plants.
The temperature, humidity, light levels and soil moisture values will also be published to
DynamoDB. Through a server (Raspberry Pi), the data will be displayed onto a flask web
page where it shows real-time data coming from the sensors. This will allow users to view
the real-time environmental conditions of the plants on the go (the latest 15 records
through a graph).
The web page will also allow users to control the water pump and decide whether they wish
to water the plants automatically or manually. They can turn on or off the water pump
whenever they wish to, thus making it very convenient if users wish to water their plants
even when they are not around.
D. Final Setup
Dashboard page:
Realtime values of the
temperature, humidity, sol
moisutre and light level
Graphs page:
Historical data of
the past 15 records
for temperature,
humidity and soil
moisture level and
light level readings
Section 2
Hardware Requirements
A. Hardware checklist
Smart Garden
Item Quantity
1) Raspberry Pi 3 Model B 1
2) T-Cobbler kit 1
3) Breadboard 1
4) Arduino UNO 1
5) DHT11 Temperature & Humidity Sensor 1
6) Soil Moisture Sensor 1
7) Water Pump (5V DC Motor) 1
8) Silicone Tubes 2
9) LED (red) 1
10) LED (yellow) 1
11) i2c LCD Screen (16x2) 1
12) Light-Dependant Resistor (LDR) 1
13) PN2222 Transistor 1
14) 1N4001 Diode 1
15) 220 Ω Resistor 3
16) 10k Ω Resistor 2
17) Jumper wires 26
18) Alligator jumper wires 2
19) USB 2.0 Cable 1
Section 3
Setting up the hardware
A. Connect Arduino to Raspberry Pi
Task
Task
Task
C. Connect LED
Task
Task
E. Connect DC Motor
Task
Task
Task
Section 4
Software Setup
It is important to install and setup essential packages on the Raspberry Pi and Arduino UNO before
we proceed with the programming section of the application.
Task
a) As we will be using the DHT11 Sensor, we will have to install the DHTLib library to the
Arduino through the Raspberry Pi.
The DHTLib library will be used to read the temperature and humidity values from the
DHT11 and can be downloaded from:
https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib
b) Once the zip files are downloaded, open up the Arduino IDE go to Sketch > Include
Library > Add Library and select the DHTLib.zip files.
Task
C. Prepare folders
Task
Section 5.1
Setting Up Amazon Web Service (AWS) account
Sign in to the AWS IoT Console
Task
c) In the AWS
Management Console,
search for “IoT Core”
to access the AWS IoT
service.
d) On the Welcome
page, click on
the “Get started”
button.
Task
a) In the left navigation bar, click the “Manage” option to expand it, and select
“Things”.
b) Click on “Create” to
create a thing.
Task
d) Name your thing with whatever name you want, here we will name it
“smartgardenThing”. Then click next.
Create Certificates
Task
a) Next let’s create a certificate for you thing by clicking the “Create certification” button for
“One-click certification creation”.
Task
Task
Task
d) Click “Create”.
Task
b) The certificate that you created earlier will be shown. Check on the certificate by ticking
the checkbox and click on the “Actions” button and select “Attach Policy”.
Task
Task
Task
a) In the left navigation bar, click the “Manage” option to expand it, and select “Things”.
Task
b) Click into the Thing you created and navigate to the “Interact” tab.
Copy the REST API Endpoint and save it somewhere, you will need it later.
Section 5.2
Setting Up DynamoDB
Create AWS Role
If you do not have a paid AWS account, you should continue with the steps for this section, else skip
to the next.
Task
Task
Key in a rolename.
Task
Task
Task
Task
username: usr
password: pwd
Task
a) Going back to the AWS IoT console, in the left navigation bar,
click on “Act”. Then click “Create”.
Task
Task
e) Select the action to “Split message into multiple columns of a DynamoDB table
(DynamoDBv2)” and click “Configure action”.
g) If you are using a AWS Paid account, click “Create a new role”. Then select the newly
created role and click “Update role”.
If you are using a AWS Educate account, you will not be able to create a new role.
Instead, just choose the one you created in Section 8 Step A (iotlab11role) from the drop-
down list and click “Update Role”
h) This brings you back to the Create a Rule page. Click “Create rule” at the bottom right
hand side of the screen to create the rule.
i) Create rules for the other tables as well, with the following fields:
Task
Section 5.3
Configure AWS CLI
Configure AWS CLI
Make sure you have your AWS Access Key and Secret Access Key.
Task
a) On your Raspberry Pi, navigate to the directory where your Python code will be stored
cd ~/ca2/smartgarden
b) Type the following command in your Raspberry Pi terminal so that you can use the
AWS CLI to configure your credentials file:
aws configure
c) Enter your Access Key ID and Secret Access Key as well as region name (us-west-2 is
Oregon, which was what we set at the start)
Section 6.1
Coding the Application – Smart Garden
The highlighted parts of the code are the ones you have to change according to what you have
created.
Certifications
Task
a) Transfer the certifications you saved earlier (Section 5.1 C) to the folder ¬/ca2 in your
RPi by using Filezilla.
smartgarden.ino
First, we will create an Arduino program that reads the values of the DHT11 sensor (temperature
and humidity), LDR sensor (light values), and the soil moisture sensor.
Also the program will light up the red LED if the soil moisture level is too high (the higher it is ,
the drier the soil) and the yellow LED if the room is too dark.. Finally, the program will control
the motor and automate the watering system.
It will send the values read to the RPi through serial communication to store it in the database,
and receive back data from the RPi that will be used to control the motor.
Task
b) Open the Arduino IDE on the RPi and save the new file as smartgarden.ino. The file will
be saved in the ~/sketchbook/smartgarden folder of your RPi.
c) Copy and paste the code below to the newly created file.
#include <dht.h> // dht lib
#define DHT11_PIN 7
Task
float temp;
float hum;
int ldrValue;
int redLEDPin = 13; // set red led to pin 13 (water)
int yellowLEDPin = 12; // set yellow led to pin 12 (ldr)
int ldrPin = A1; // set ldr to A1
int motorPin = 3; // set motor to pin 3
/* 'A': auto
'M': manual
'O': on
'F': off
*/
char status;
int lightLevel;
void setup() {
Serial.begin(9600);
//Serial.println("Soil Moisture Sensor start reading");
pinMode(redLEDPin, OUTPUT);
pinMode(yellowLEDPin, OUTPUT);
pinMode(ldrPin, INPUT);
pinMode(motorPin, OUTPUT);
delay (2000);
}
void loop() {
// Receive data from server
if (Serial.available() ) {
status = Serial.read();
}
chk = DHT.read11(DHT11_PIN);
temp = DHT.temperature;
hum = DHT.humidity;
soilValue = analogRead(soilPin);
ldrValue = analogRead(ldrPin);
Serial.println(temp);
Serial.println(hum);
Serial.println(soilValue);
Serial.println(ldrValue);
if (status == 'A') {
if (soilValue > 500) {
analogWrite(motorPin, 200);
digitalWrite(redLEDPin, HIGH);
} else {
digitalWrite(redLEDPin, LOW);
analogWrite(motorPin, LOW);
}
} else if (status == 'M' || status == 'F') {
if (soilValue > 500) {
analogWrite(motorPin, LOW);
digitalWrite(redLEDPin, HIGH);
} else {
digitalWrite(redLEDPin, LOW);
analogWrite(motorPin, LOW);
}
Task
if (ldrValue>=300) {
digitalWrite(yellowLEDPin, HIGH);
} else {
digitalWrite(yellowLEDPin, LOW);
}
delay(4000);
}
aws_pubsub scripts
Next, we will create aws_pubsub scripts (aws_pubsub_readings.py, aws_pubsub_status.py) that
will be used to send the readings from the sensors to the database, and receive the status of the
motor controlled by the web server from the database.
Task
Task
print("--------------\n\n")
my_rpi = AWSIoTMQTTClient("basicPubSub")
my_rpi.configureEndpoint(host, 8883)
my_rpi.configureCredentials(rootCAPath, privateKeyPath, certificatePath)
lcd.text('Humidity: {:.2f}%'.format(hum), 1)
lcd.text('Temp: {:.2f} C'.format(temp), 2)
sleep(2)
lcd.clear()
lcd.text('Moisture: {:d}'.format(soil), 1)
lcd.text('Light Level: {:d} C'.format(light), 2)
sleep(2)
lcd.clear()
loopCount = loopCount+1
message = {}
message["id"] = "id_smartgarden"
import datetime as datetime
now = datetime.datetime.now()
message["datetimeid"] = now.isoformat()
message["temperature"] = temp
message["humidity"] = hum
message["moisture"] = soil
message["light"] = light
import json
my_rpi.publish("smartgarden/readings", json.dumps(message), 1)
Task
my_rpi = AWSIoTMQTTClient("basicPubSub")
my_rpi.configureEndpoint(host, 8883)
my_rpi.configureCredentials(rootCAPath, privateKeyPath, certificatePath)
response = table.query(KeyConditionExpression=Key('id').eq('id_status'),
ScanIndexForward=False
)
items = response['Items']
n=1
data = items[:n]
uStatus = data[0]['status']
status = uStatus.encode('latin-1')
print(status)
ser.write(status)
sleep(4)
Task
c) Create a scripts.py file and copy the code below. This script will allow you to run the
other two scripts at the same time in one script.
from multiprocessing import Process
def script1():
while True:
import aws_pubsub_readings
def script2():
while True:
import aws_pubsub_status
if __name__ == '__main__':
print ('Running scripts...')
proc1 = Process(target = script1)
proc1.start()
print ('Reading script running...')
d) Transfer the fles into the ~/smartgarden folder in the RPi using FileZilla.
dynamodb.py
Next, we will create dynamodb.py where functions are defined to fetch and send data to and
from the DynamoDB to the web app.
Task
def login():
try:
dynamodb = boto3.resource('dynamodb', region_name='us-west-2')
table = dynamodb.Table('YOUR SMARTGARDEN_LOGIN TABLE NAME')
response = table.scan()
Task
items = response['Items']
return items
except:
import sys
print(sys.exc_info()[0])
print(sys.exc_info()[1])
def get_data():
try:
dynamodb = boto3.resource('dynamodb', region_name='us-west-2')
table = dynamodb.Table('YOUR SMARTGARDEN_READINGS TABLE NAME')
startdate = date.today().isoformat()
response =
table.query(KeyConditionExpression=Key('id').eq('id_smartgarden') &
Key('datetimeid').begins_with(startdate),
ScanIndexForward=False
)
items = response['Items']
def get_chart_data():
try:
startdate = date.today().isoformat()
response =
table.query(KeyConditionExpression=Key('id').eq('id_smartgarden') &
Key('datetimeid').begins_with(startdate),
ScanIndexForward=False
)
items = response['Items']
def get_status():
try:
dynamodb = boto3.resource('dynamodb', region_name='us-west-2')
table = dynamodb.Table('YOUR SMARTGARDEN_STATUS TABLE NAME')
Task
startdate = date.today().isoformat()
response =
table.query(KeyConditionExpression=Key('id').eq('id_status') &
Key('datetimeid').begins_with(startdate),
ScanIndexForward=False
)
items = response['Items']
n=1
data = items[:n]
return data
except:
import sys
print(sys.exc_info()[0])
print(sys.exc_info()[1])
def send_status(status):
try:
# print("status", status)
dynamodb = boto3.resource('dynamodb', region_name='us-west-2')
table = dynamodb.Table('YOUR SMARTGARDEN_STATUS TABLE NAME')
now = dt.datetime.now()
new_item = {
"id": "id_status",
'datetimeid': now.isoformat(),
'status': status
}
table.put_item(Item = new_item)
except:
import sys
print(sys.exc_info()[0])
print(sys.exc_info()[1])
if __name__ == "__main__":
query_data_from_dynamodb()
b) Transfer the file into the ~/smartgarden folder in the RPi using FileZilla.
jsonconverter.py
Next, we will create jsonconverter.py where functions are defined to convert data to json.
Task
class GenericEncoder(json.JSONEncoder):
def data_to_json(data):
json_data = json.dumps(data,cls=GenericEncoder)
# print(json_data)
return json_data
d) Transfer the file into the ~/smartgarden folder in the RPi using FileZilla.
Task
a) For our web interface, I used the Paper Dashboard Bootstrap Template by Creative Tim
and it can be downloaded from:
https://www.creative-tim.com/product/paper-dashboard
Create 2 new folders called templates and static in a folder called flaskapp in
your laptop inside the ~/smartgarden folder. Copy the required files in the
assets folder from the downloaded template and paste it in the static folder,
this includes the css, js, img and fonts folder.
Create the following html pages in the templates folder.
o dashboard.html
o graph.html
o login.html
Task
o navbar.html
o template.html
Create a main.css file in the static/css folder.
Create a main.js file in the static/js folder.
Delete any unnecessary files
The final folder tree directory should look like the following:
Task
Task
<div class="row">
<div class="col-md-4">
<div class="card">
<div class="header">
<h4 class="title">Automated Watering</h4>
</div>
<div class="content">
<center>
<label class="toggleBtn">
<input class="switch-input" id="autoSwitch"
type="checkbox" onclick="auto()" />
<span class="switch-label" data-on="on" data-
off="off"></span>
<span class="switch-handle"></span>
</label>
</center>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="header">
<h4 class="title">Manual Watering</h4>
</div>
<div class="content">
<center>
<label class="toggleBtn">
<input class="switch-input switch2-input"
id="manualSwitch" type="checkbox" onclick="manual()" />
<span class="switch-label switch2-label" data-on="on"
data-off="off"></span>
<span class="switch-handle switch2-handle"></span>
</label>
</center>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}
Task
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="header">
<h4 class="title">Temperature</h4>
<p class="category">Realtime temperature reading</p>
</div>
<div class="content">
<div id="tempChart" class="ct-chart ct-major-twelfth"></div>
</div>
</div>
</div>
<div class="col-md-12">
<div class="card">
<div class="header">
<h4 class="title">Humidity</h4>
<p class="category">Realtime humidity reading</p>
</div>
<div class="content">
<div id="humChart" class="ct-chart ct-major-twelfth"></div>
</div>
</div>
</div>
<div class="col-md-12">
<div class="card">
<div class="header">
<h4 class="title">Soil Moisture Level</h4>
<p class="category">Realtime soil moisture level reading</p>
</div>
<div class="content">
<div id="soilChart" class="ct-chart ct-major-twelfth"></div>
</div>
</div>
</div>
<div class="col-md-12">
<div class="card">
<div class="header">
<h4 class="title">Light Level</h4>
<p class="category">Realtime light level reading</p>
</div>
<div class="content">
<div id="lightChart" class="ct-chart ct-major-twelfth"></div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}
Task
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/png" sizes="96x96" href="{{
url_for('static', filename='img/logo.png') }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
{% if title %}
<title>Smart Garden - {{ title }}</title>
{% else %}
<title>Smart Garden</title>
{% endif %}
</head>
<body>
<div class="wrapper">
<div class="login">
Task
<div class="form-group">
{{ form.username.label(class="form-control-label") }}
{% if form.username.errors %}
{{ form.username(class="form-control form-control-lg is-
invalid") }}
<div class="invalid-feedback">
{% for error in form.username.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.username(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.password.label(class="form-control-label") }}
{% if form.password.errors %}
{{ form.password(class="form-control form-control-lg is-
invalid") }}
<div class="invalid-feedback">
{% for error in form.password.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.password(class="form-control form-control-lg") }}
{% endif %}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
<footer class="footer-login">
<div class="container-fluid">
<div class="copyright pull-right">
IOT CA2 Project by <span class="text-info">I Owe Tea</span>
</div>
</div>
</footer>
</div>
</div>
</body>
Task
<!-- Paper Dashboard Core javascript and methods for Demo purpose -->
<script src="{{ url_for('static', filename='js/paper-dashboard.js')
}}"></script>
</html>
<div class="sidebar-wrapper">
<div class="logo">
<a href="#" class="simple-text">SMART GARDEN</a>
</div>
<ul class="nav">
{% if active == 'dashboard' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="{{ url_for('dashboard') }}">
<i class="fas fa-seedling"></i>
<p>Dashboard</p>
</a>
</li>
{% if active == 'graph' %}
<li class="active">
{% else %}
<li>
{% endif %}
<a href="{{ url_for('graph') }}">
<i class="ti-pie-chart"></i>
<p>Graphs</p>
</a>
</li>
</ul>
</div>
</div>
Task
<div class="main-panel">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar bar1"></span>
<span class="icon-bar bar2"></span>
<span class="icon-bar bar3"></span>
</button>
{% if active == 'dashboard' %}
<a class="navbar-brand" href="{{ url_for('dashboard')
}}">Dashboard</a>
{% elif active == 'graph' %}
<a class="navbar-brand" href="{{ url_for('graph') }}">Graphs</a>
{% endif %}
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li>
<a href="{{ url_for('logout') }}">
<i class="fas fa-sign-out-alt"></i>
<p>Logout</p>
</a>
</li>
</ul>
</div>
</div>
</nav>
<footer class="footer">
<div class="container-fluid">
<div class="copyright pull-right">
IOT CA2 Project by <span class="text-info">I Owe Tea</span>
</div>
</div>
</footer>
</div>
{% endblock navbar %}
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/png" sizes="96x96" href="{{
url_for('static', filename='img/logo.png') }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
Task
{% if title %}
<title>Smart Garden - {{ title }}</title>
{% else %}
<title>Smart Garden</title>
{% endif %}
</head>
<body>
<div class="wrapper">
</div>
</body>
Task
<!-- Paper Dashboard Core javascript and methods for Demo purpose -->
<script src="{{ url_for('static', filename='js/paper-dashboard.js')
}}"></script>
</html>
.form-signin {
width: 100%;
max-width: 500px;
padding: 50px 15px;
margin: auto;
font-weight: 400;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.footer-login {
position: fixed!important;
bottom: 15px;
right: 15px;
}
/* Toggle buttons */
.toggleBtn {
position: relative;
display: block;
width: 90px;
Task
height: 40px;
padding: 3px;
bottom: 5px;
border-radius: 30px;
}
.switch-input, .icons {
position: absolute;
width: 0;
height: 0;
opacity: 0;
}
.switch-label {
position: relative;
display: block;
height: inherit;
font-size: 12px;
text-transform: uppercase;
background: #bdc1c8;
border-radius: inherit;
cursor: pointer;
}
.switch-label:before, .switch-label:after {
position: absolute;
top: 30%;
-webkit-transition: inherit;
-moz-transition: inherit;
-o-transition: inherit;
transition: inherit;
}
.switch-label:before {
content: attr(data-off);
right: 9px;
color: #6b7381;
}
.switch-label:after {
content: attr(data-on);
left: 9px;
color: #FFFFFF;
}
.switch-input:checked ~ .switch-label {
background: #29b5a8;
}
.switch2-input:checked ~ .switch2-label {
background: #ff8300;
}
.switch-input:checked ~ .switch-label:before {
opacity: 0;
}
.switch-input:checked ~ .switch-label:after {
opacity: 1;
}
.switch-handle {
position: absolute;
top: 8px;
left: 9px;
width: 29px;
height: 29px;
background: white;
background-image: -webkit-linear-gradient(top, #FFFFFF 40%, #f0f0f0);
Task
border-radius: 100%;
}
.switch-input:checked ~ .switch-handle {
left: 52px;
background-color: #29b5a8;
box-shadow: 0 0 1px #29b5a8;
}
.switch2-input:checked ~ .switch2-handle {
background-color: #ff8300;
box-shadow: 0 0 1px #ff8300;
}
input[type="checkbox"]:disabled + .switch-label,
input[type="checkbox"]:disabled + .switch-handle
{
filter: contrast(70%);
cursor: not-allowed;
}
/* Transition
========================== */
.switch-label, .switch-handle {
transition: All 0.4s ease;
-webkit-transition: All 0.4s ease;
-moz-transition: All 0.4s ease;
-o-transition: All 0.4s ease;
}
/* Slider */
*, *:before, *:after {
box-sizing: border-box;
}
.slidecontainer {
margin: 20px 20px 11px;
}
.slidecontainer {
width: 100%;
}
.slider {
-webkit-appearance: none;
width: 70%!important;
height: 10px;
border-radius: 5px;
background: #d7dcdf;
outline: none;
padding: 0;
margin: 0;
display: inline-block!important;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #2c3e50;
cursor: pointer;
transition: background 0.15s ease-in-out;
Task
}
.slider::-webkit-slider-thumb:hover {
background: #1abc9c;
}
.slider:active::-webkit-slider-thumb {
background: #1abc9c;
}
.slider::-moz-range-thumb {
width: 20px;
height: 20px;
border: 0;
border-radius: 50%;
background: #2c3e50;
cursor: pointer;
transition: background 0.15s ease-in-out;
}
.slider::-moz-range-thumb:hover {
background: #1abc9c;
}
.slider:active::-moz-range-thumb {
background: #1abc9c;
}
.slider:focus::-webkit-slider-thumb {
box-shadow: 0 0 0 3px #fff, 0 0 0 6px #1abc9c;
}
.sliderValue {
display: inline-block;
position: relative;
/* width: 60px; */
color: #fff;
line-height: 20px;
text-align: center;
border-radius: 3px;
background: #2c3e50;
padding: 5px 10px;
margin-left: 8px;
font-size: 15px;
}
.sliderValue:after {
position: absolute;
top: 8px;
left: -7px;
width: 0;
height: 0;
border-top: 7px solid transparent;
border-right: 7px solid #2c3e50;
border-bottom: 7px solid transparent;
content: '';
}
::-moz-range-track {
background: #d7dcdf;
border: 0;
}
input::-moz-focus-inner, input::-moz-focus-outer {
border: 0;
}
Task
function getStatus() {
jQuery.ajax({
url: "/api/status",
type: "POST",
success: function (ndata) {
// console.log(ndata[0].status);
status = ndata[0].status;
if (status == "A") {
autoSwitch.checked = true;
manualSwitch.disabled = true;
manualSwitch.checked = false;
} else if (status == "M" || status == "F") {
autoSwitch.checked = false;
manualSwitch.checked = false;
} else if (status == "O") {
autoSwitch.checked = false;
manualSwitch.checked = true;
} else {
autoSwitch.checked = true;
manualSwitch.disabled = true;
manualSwitch.checked = false;
}
}
})
}
function auto() {
let autoStatus;
if (autoSwitch.checked) {
autoStatus = "A";
manualSwitch.disabled = true;
manualSwitch.checked = false;
} else {
autoStatus = "M";
manualSwitch.disabled = false;
}
// console.log(autoStatus);
$.ajax({
url: "changeStatus/" + autoStatus
})
function manual() {
let manualStatus;
if (manualSwitch.checked) {
manualStatus = "O";
} else {
manualStatus = "F";
}
// console.log(manualStatus);
$.ajax({
url: "changeStatus/" + manualStatus
})
Task
$('#tempValue').html(tempValue);
$('#humValue').html(humValue);
$('#soilValue').html(soilValue);
$('#lightValue').html(lightValue);
}
})
}
chartData.forEach((e) => {
tempArr.push(e.temperature);
humArr.push(e.humidity);
soilArr.push(e.moisture);
lightArr.push(e.light);
}
})
}
Task
// Charts
function createGraph(data, newTime, newChart) {
let chartData = {
labels: newTime,
series: [data]
};
// console.log(chartData);
let options = {
axisY: {
onlyInteger: true
},
fullWidth: true,
width: '100%',
height: '100%',
lineSmooth: true,
chartPadding: {
right: 50
}
};
setInterval(function () {
getData();
getChartData();
}, 5000);
})
i) Transfer the flaskapp folder into the ~/smartgarden folder in the RPi using FileZilla.
Server files
Lastly, we will create the files that will act as a server for the Flask app. We will be structuring the
files in packages to make it more organised.
Task
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
app = Flask(__name__)
app.secret_key = os.urandom(12)
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
# login
@app.route("/login", methods=['GET', 'POST'])
def login():
if session.get('logged_in'):
return redirect(url_for('dashboard'))
else:
form = LoginForm()
if form.validate_on_submit():
data = dynamodb.login()
for d in data:
if form.username.data == d['username'] and form.password.data ==
d['password']:
session['logged_in'] = True
Task
return redirect(url_for('dashboard'))
else:
flash('Login Unsuccessful. Please check username and password',
'danger')
return render_template('login.html', title='Login', form=form)
# logout
@app.route("/logout")
def logout():
session.pop('logged_in', None)
return redirect(url_for('login'))
# pages
@app.route("/")
@app.route("/dashboard")
def dashboard():
if not session.get('logged_in'):
return redirect(url_for('login'))
else:
return render_template('dashboard.html', title='Dashboard',
active='dashboard')
@app.route("/graph")
def graph():
if not session.get('logged_in'):
return redirect(url_for('login'))
else:
return render_template('graph.html', title='Graph', active='graph')
# api routes
@app.route("/api/getData", methods=['POST', 'GET'])
def api_getData():
if request.method == 'POST':
try:
data = jsonc.data_to_json(dynamodb.get_data())
loaded_data = jsonc.json.loads(data)
# print(loaded_data)
return jsonify(loaded_data)
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
return None
Task
data = jsonc.data_to_json(dynamodb.get_status())
loaded_data = jsonc.json.loads(data)
# print(loaded_data)
return jsonify(loaded_data)
status = loaded_data[0].status
return status
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
return None
@app.route("/changeStatus/<status>")
def changeStatus(status):
try:
dynamodb.send_status(status)
return status
except:
print(sys.exc_info()[0])
print(sys.exc_info()[1])
return None
e) From your laptop, transfer the server.py file into the ~/smartgarden folder, and the
__init__.py, routes.py and forms.py files into the ~/smartgarden/flaskapp folder in the
RPi using FileZilla.
Section 6.1
Running the Application – Smart Garden
Run Arduino code
Task
a) From the Arduino IDE, upload the smartgarden.ino code by pressing the upload button.
Once it has been uploaded your hardware should start working.
Run scripts.py
Task
a) Open a new Terminal window and change directory to the ~/smartgarden folder:
cd ~/smartgarden
b) Once you have uploaded the Arduino code, run the scripts.py file immediately as it has
to be in sync with the Arduino:
sudo python scripts.py
Run server.py
Task
a) On your RPi, open another Terminal window and change directory to the ~/smartgarden
folder:
cd ~/smartgarden
Task
View Webpage
Task
a) On your laptop, open your browser and enter your RPi’s IP address along with :5000 as
shown (x.x.x.x is your RPi’s IP address):
http://x.x.x.x:5000
b) If everything went well, you should see a similar output where you are asked to login:
Task
c) After logging in, you will be brought to the dashboard page where it shows the realtime
values of the smart garden environment.
It is then followed by the two switches. By turning on the Automated Watering switch,
the system will water the plant when the moisture level is higher than 400 (the higher
then drier). And by turning it off, users can choose to water the plants manually by using
the Manual Watering switch instead.
Task
d) You can toggle to the Graphs page by clicking on “Graphs” in the navigation bar at the left
side of the page. The graphs page shows three graphs that displays the historical data of
the latest 15 records of the temperature, humidity and soil moisture level.
Task
e) Finally, you can choose to logout of the web page by clicking on the logout button located
at the top right of the web page.