As part of the PlantBot project, I wanted a way to look at sensor data over the internet. These sensors are moisture, light and pressure. The main one is moisture, the other two were just added in because I had the parts lying around.
Here is a block diagram outlining each of the steps to go from reading the analog sensor values to graphing them on a webpage:
Step 1: Reading sensor values with arduino and sending them over UART:
Sensors used:
-LDR
-MPX4115A Pressure Sensor
-Moisture Sensor
I made the moisture sensor using some galvanised nails. First just solder some wires to the top of the nails. Then cover most of the nail with heatshrink, just leaving the tips exposed.
The arduino nano has a USB-Serial converter on board so it can be plugged directly into the pi via usb and start sending serial data.
Code:
const int PressurePin = A0; const int LightPin = A2; const int MoisturePin = A5; int PressureVal = 0; int LightVal = 0; int MoistureVal = 0; void setup() { Serial.begin(9600); } void loop() { Serial.flush(); while(!Serial.available()); //wait for character from raspi delay(1000); PressureVal = analogRead(PressurePin); //read analog pins LightVal = analogRead(LightPin); MoistureVal = analogRead(MoisturePin); Serial.print(PressureVal); //send adc values over uart to pi Serial.print(","); Serial.print(LightVal); Serial.print(","); Serial.print(MoistureVal); Serial.print("\n"); }
This arduino program waits to receive a serial character from the pi. Once received it will read all of the sensors and send back the sensor values to the pi via uart.
Step 2: Reading sensor values with Python and placing them in a MySQL database:
#!/usr/bin/python import serial import MySQLdb import time db = MySQLdb.connect(host="66.147.244.233", user="wattnoti_user", passwd="fakepass123", db="wattnoti_plantbot") cur = db.cursor() port = serial.Serial("/dev/ttyUSB0", baudrate = 9600,timeout=None) port.flushInput() PressureVal = 0; MoistureVal = 0; LightVal = 0; vals = [] while (port.inWaiting()==0): #keep sending char until arduino replies port.write("*") time.sleep(1) vals = (port.readline()).split(',') print vals PressureVal = int(vals[0]) LightVal = int(vals[1]) MoistureVal = int(vals[2]) cur.execute("insert into sens_vals(Pressure,Light,Moisture) values(" + str(PressureVal) + "," + str(LightVal) + "," + str(MoistureVal) + ")" ) #put adc values in mysql db cur.execute("SELECT * from sens_vals") #dataset = cur.fetchall() for debugging - print mysql rows to check sensor values were added #for row in dataset: # print row db.close()
The MySQL database was made using the terminal on the pi. Here are some pictures of the database format:
On the Pi, a cronjob is used to run the python script every 30 mins. To edit the crontab, I used sudo crontab -e and entered the following:
*/30 * * * * python /home/pi/plantbot/serial2db.py
This means that every 30 mins the sensors are read and their values placed in the MySQL database.
Step 3 : Running PHP on the server to graph values from MySQL database:
<?php // content="text/plain; charset=utf-8" define('__ROOT__', dirname(dirname(__FILE__))); require_once ('../tools/jpgraph/src/jpgraph.php'); require_once ('../tools/jpgraph/src/jpgraph_line.php'); require_once ('../tools/jpgraph/src/jpgraph_error.php'); require_once ('../tools/jpgraph/src/jpgraph_date.php'); $dates= array(); $light = array(); $pressure = array(); $moisture = array(); $i = 0; $con=mysqli_connect("66.147.244.233","wattnoti_user","physics","wattnoti_plantbot"); //Check connection if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); } mysqli_query($con,"set time_zone = '+00:00'"); $result = mysqli_query($con,"(SELECT * FROM sens_vals ORDER BY id DESC LIMIT 25) ORDER BY id ASC"); while($row = mysqli_fetch_array($result)) { $dates[$i] = strtotime($row["date"]); $light[$i] = $row["Light"]; $pressure[$i] = $row["Pressure"]; $moisture[$i] = $row["Moisture"]; $i++; } mysqli_close($con); $graph = new Graph(800,500); $graph->img->SetMargin(40,40,40,40); $graph->img->SetAntiAliasing(); $graph->SetScale("datlin"); $graph->SetShadow(); $graph->title->Set("PlantBot Sensor Readings"); $graph->title->SetFont(FF_FONT1,FS_BOLD); // Ensure anti-aliasing is off. If it is not, you can SetWeight() all day and nothing will change. $graph->img->SetAntiAliasing(false); $graph->xaxis->SetLabelAngle(45); $graph->xaxis->scale->SetDateFormat('Y:M:d:D:H:i'); $graph->legend->SetPos(0.37,0.07,'right','center'); $graph->legend->SetFrameWeight(2); $graph->legend->SetColor('black','black'); $graph->xgrid->Show(true,false); // Use 20% "grace" to get slightly larger scale then min/max of // data $graph->yscale->SetGrace(0); $graph->yaxis->title->Set("ADC Value"); $graph->yaxis->SetTitleMargin(-700); $p1 = new LinePlot($light,$dates); $p1->SetColor("blue"); $p1->SetCenter(); $p1->SetLegend("light"); $p2 = new lineplot($pressure,$dates); $p2->setColor("orange"); $p2->SetLegend("pressure"); $p3 = new lineplot($moisture,$dates); $p3->setColor("yellow"); $p3->SetLegend("moisture"); $graph->Add($p1); $graph->Add($p2); $graph->Add($p3); $p1->SetWeight(3); $p2->SetWeight(3); $p3->SetWeight(3); $graph->Stroke(); ?>
This PHP program looks kinda bulky but most of it is just jpgraph stuff to make the graph look nice. Lines 1-34 is where the MySQL db is accessed and the sensor values read in PHP arrays.
Graph Produced (Real time image):
I’m still working out some of the kinks with jpgraph so while it’s not perfect, you get the idea.
The html page I’ll be displaying all of the real time data on is located at https://wattnotions.com/html_stuff/PlantBotNet.html
As I’m writing this post now (10th January 2016), all it contains is a picture of the graph – I’ll be adding to it in the near future.
Update 1 : (10th Jan 2016)
Just planted some cress seeds in part of this plantbox I have – will manually water it (uh effort) for the next few days/weeks or however long it takes for cress seeds to grow. This will be automated soon enough by Plantbot. Stay tuned!
Hi Shane,
Nice little project! I was just wondering if there was a specific reason for not using the Pi to read the sensors? Is it due to the lack of built-in ADC? Would a PCF8591 be cheaper than using an arduino?
Cheers,
Sam
Hey Sam, Thanks! Pretty much the only reason I used an arduino nano is because I had it laying around…. I got it from china for 2 euro, not sure how much a PCF8591 costs 🙂
I’m using a pi 3 and struggling to get the raspberry pi to read from usb serial
Try googling your problem and if that doesn’t work post to an Arduino/Raspi forum. Best of luck with it.
Hi, its amazing .
Thanks