A Smart Farming System that is unlike anything you have ever seen before! Our innovative Smart Farm will deter pests and detect intruders!
Things used in this project
Hardware components
Software apps and online services
Microsoft Visual Studio Code Extension for Arduino
Github
makercase.com
Fritzing
Adobe Illustrator
Hackster.io
Adafruit.IO
Hand tools and fabrication machines
Laser cutter (generic)
Plier, Long Nose
Plier, Cutting
Wire Stripper, Serrated Plier Nose
Hot glue gun (generic)
Story
This innovative smart farm system will alleviate the tedious but crucial work that farmers all over the globe suffer from. The system will be able to communicate with the farmers anywhere that there is a smart device with Bluetooth capabilities. In comparison to previous farming systems, this smart farming system is the tesla of farming systems because it utilizes the newest in cutting edge technology in order to boost yields and maintain farmer morale!
The PURPOSE of this project came about because of real-life experiences during New Mexico’s first hemp farming season in 2019.
Hemp legalization occurred under the 2019 Farm Bill, which was passed on December 20, 2018; however, an approved USDA Domestic Hemp Production Program was not established until March 22, 2021. Since farmers had no established guidance from the USDA; the first 2 hemp farming seasons were negatively impacted. One of the hardest hit aspects of hemp farming was PESTCONTROL. This was because there were no approved pesticides to keep hemp crops free from diseases and pests. With more farms going organic, the pesticide problem needs to be addressed. Another problematic factor hemp farmers are dealing with is physical SECURITY and safe keeping of hemp. Hemp contains Delta 9 tetrahydrocannabinol (THC) which is listed under Schedule I by US federal law[16] under the Controlled Substances Act. The THC content creates a unique aspect, theft. Theft is problematic not only because of the loss in yield but also because of the farmer’s legal responsibility to maintain control of all THC production. Another factor farmers dealt with and still are dealing with is controlling hemp POLLINATION. When hemp is pollinated, it begins the process of seed propagation and in turn DECREASES trichome production. Trichomes are the mechanism by which hemp produces cannabinoids, such as cannabidiol (CBD) Majority of New Mexican farmers grew high CBD hemp strains to produce, manufacture and sell high quality CBD hemp OIL not seeds.
The Smart Farming System houses a weather station and a plant monitoring system. The weather station is comprised of 2 components and a cloud- based website. The first component is the BME280 which is a temperature, humidity and pressure sensor. The second component is a monochrome I2C OLED Display unit with a 128 x 64 resolution dot matrix panel. The weather data can be accessed from anywhere in the world via Adafruit.io which provides real-time data on the status of the crop’s environment. The plant monitoring system comprises of two components, a soil sensor and the Grove Dust sensor. Both of these components are rather simple in both implantation and function; however, they both play critical roles in alleviating burden from farmers. The soil sensor is implanted directly into the ground via stake, and gathers the moisture readings from the surrounding region in order to aid the farmer in determining plant health. The dust sensor sits inside of our fabricated box in order to gather pollen readings in a valiant attempt to aid the farmer in determining the overall pollination levels in the surrounding region. Both of these two systems can be monitored in a user friendly interface known as Adafruit.IO dashboard, in which, the data has already been collected, converted, and crafted to be aesthetically pleasing.
The Smart Farming System also houses a security system and pest deterrent system. The components necessary for these functions are the Ultrasonic Sensor, the Stepper motor and it's driver board. The Stepper motor's only function is to turn the Ultrasonic sensor 180 degrees and back to its starting position. The main magic comes from the Ultrasonic sensor! This advanced sensor coupled with our innovative code and thinking, can pulse out frequencies that will naturally deter pests from the given region (26 feet). Furthermore, the Ultrasonic sensor also has the capability to simultaneously count the amount of time between each given pulse and its return in order to determine not only distance, but INTRUDERS as well! This component will notify the farmer about any changes in location pulsing via SMS text messaging through Zapier.com as well as by changing the colors on the Adafruit.IO dashboard.
Finally, the Smart Farming System has two vital functions! The second to last is GPS and fall detection systems. The GPS functions are utilized in determining the location of the unit but this function is catered more towards large farm field owners. Furthermore, the GPS constantly populates a street map of real time coordinates on the Adafruit.IO dashboard. The fall detection system utilizes the MPU 6050 component in order to constantly give back data as to the orientation of the box. This data is expected to consistently give back the same date (primarily because the box stays in place). However, if the MPU reads a change in data on any of the axis planes (Z, X, Y), it will notify the farmer via SMS text message as well as changing the colors on the Adafruit.IO dashboard.
Here is the link to our Adafruit.IO dashboard: IO - Smart Farming System(adafruit.com)
Here is the link to our GitHub repository: Smart Farming Project (github.com)
Stephanie working hard
Picture of the enclosure
Stephanie holding the robo head
The laser cut outs
Kareem just doing his job
Stephanie cradling the baby
Schematics
Fritzing Diagram for Smart Farming System
This the Fritzing diagram
Code
Smart Farming Code
C/C++
To work the farm
/*
* Project Master-Code
* Description: The Smart Farming System Master Code
* Author: Stephanie Perea and Kareem Crum
* Date: 19-MAY-2021
*/
#include <TinyGPS++/TinyGPS++.h>
#include <Adafruit_MQTT.h>
#include "math.h"
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"
#include "Adafruit_BME280.h"
#include "Adafruit_Sensor.h"
#include "Particle.h"
#include "Stepper.h"
#include "credentials.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET D4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
#define XPOS 0
#define YPOS 1
#define echoPin D6 // attach pin D6 Arduino to pin Echo of HC-SR04
#define trigPin D7 //attach pin D7 Arduino to pin Trig of HC-SR04
//Global State
TCPClient TheClient;
//Adafruit BME class
Adafruit_BME280 bme;
//Adafruit OLED Class
Adafruit_SSD1306 display(OLED_RESET);
//Stepper Class
Stepper myStepper(2048, D5, D3, D4, D2);
//MQTT Client Class
Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY);
//TinyGPS++ Object
TinyGPSPlus gps;
//Feeds
Adafruit_MQTT_Publish Trigger = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/UltraSonic");
Adafruit_MQTT_Publish Satellites = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Satellites");
Adafruit_MQTT_Publish GPS = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Location");
Adafruit_MQTT_Publish Moist = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/SoilMoisture");
Adafruit_MQTT_Publish Pressure = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Pressure");
Adafruit_MQTT_Publish Humid = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Humidity");
Adafruit_MQTT_Publish Temp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Temperature");
Adafruit_MQTT_Publish Dust = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/DustSensor");
Adafruit_MQTT_Publish FallSense = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Acceleration");
//Variable for BMe
float tempC;
float humidRH;
float pressPA;
float tempF;
float inHg;
//Variables for Soil Sensor
int soilSensor = A1;
int soilMoisturePercent;
int soilMoistureValue;
//Variables for DustSensor
unsigned long dustTime;
unsigned long duration;
unsigned long lastMQTT;
unsigned long lastPub;
int dustSensor = A0;
float dustSense;
unsigned long lowpulseoccupancy = 0;
float concentration = 0;
float ratio = 0;
//Variables for UltraSonic Sensor
long amount; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement
bool intruder;
//Variables for Stepper and OLED
const int stepsRev = 2048;
int16_t stepperSpeed=15;
int16_t stepperSteps;
//Variables for GPS
const unsigned long PUBLISH_PERIOD = 120000;
const unsigned long SERIAL_PERIOD = 5000;
const unsigned long MAX_GPS_AGE_MS = 10000; // GPS location must be newer than this to be considered valid
const int UTC_offset = -6;
unsigned long lastSerial = 0;
unsigned long lastPublish = 0;
unsigned long startFix = 0;
bool gettingFix = false;
char buffer[50];
uint8_t hr,mn,se,sat;
float lat,lon,alt;
//Variables for Acceleromotor
byte accel_x_h, accel_x_L;
int16_t accel_x;
float accelX;
byte accel_y_h, accel_y_L;
int16_t accel_y;
float accelY;
byte accel_z_h, accel_z_L;
int16_t accel_z;
float accelZ;
float accelTot;
bool MPUfall = false;
float MPUValue = 0.0;
const float fall = 1.0;
SYSTEM_MODE(SEMI_AUTOMATIC);
// setup() runs once, when the device is first turned on.
void setup()
{
// Put initialization like pinMode and begin functions here.
pinMode(soilSensor, INPUT);
pinMode(dustSensor, INPUT);
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
dustTime = millis();
Serial.begin(9600);
//I2C Setup
Wire.begin();
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
//GPS Setup
Serial1.begin(9600);
startFix = millis();
gettingFix = true;
Serial.println(F("DeviceExample.ino"));
Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module"));
Serial.print(F("Testing TinyGPS++ library v. "));
Serial.println(TinyGPSPlus::libraryVersion());
Serial.println(F("by Mikal Hart"));
Serial.println();
//OLED Setup
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
helloWorld();
Serial.printf("Hello World \n");
bool status;
status = bme.begin(0x76);
myStepper.setSpeed(15);
myStepper.step(0);
Serial.printf("Connecting to Internet \n");
WiFi.connect();
while(WiFi.connecting())
{
Serial.printf(".");
delay(100);
}
Serial.printf("\n Connected!!!!!! \n");
//UltraSonic Sensor Setup
Serial.println("Ultrasonic Sensor HC-SR04 Test"); // print some text in Serial Monitor
Serial.println("with Argon");
}
// loop() runs over and over again, as quickly as it can execute.
void loop()
{
// The core of your code will likely live here.
codingFunction();
printValues();
adafruitPublish();
MQTT_connect();
}
void helloWorld()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(20,5);
display.println("GPS Initializing");
display.display();
}
void codingFunction()
{
//Code for Stepper Motor
myStepper.setSpeed(7);
myStepper.step(1024);
delay(2000);
myStepper.step(-1024);
delay(2000);
//Code for Dust Sensor
duration = pulseIn(dustSensor, LOW);
lowpulseoccupancy = lowpulseoccupancy + duration;
if ((millis()-dustTime) >= 30000)
{
ratio = lowpulseoccupancy/(30000*10.0);
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62;
if(concentration > 1){
dustSense = concentration;
}
lowpulseoccupancy = 0;
dustTime = millis();
}
//Code for Soil Sensor
soilMoistureValue = analogRead(soilSensor);
Serial.printf("Soil moisture is %i\n", soilMoistureValue);
soilMoisturePercent = map(soilMoistureValue, 1800, 3500, 100, 0);
//Code for UltraSonic Sensor
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
amount = pulseIn(echoPin, HIGH);
Serial.println("The Data is:");
// Calculating the distance
distance = amount * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
if(distance <=96)
{
intruder = true;
adafruitPublish();
}
//Code for BME
tempC = bme.readTemperature();
tempF = map(tempC,0.0,100.0,32.0,212.0);
pressPA = bme.readPressure();
inHg = pressPA/3386.389;
humidRH = bme.readHumidity();
//Code for Acceleromotor
float accelZ, accelX, accelY;
delay(1000);
findAcceleration();
Wire.requestFrom(0x68, 6, true);
accel_x_h = Wire.read();
accel_x_L = Wire.read();
accel_x = accel_x_h << 8 |accel_x_L;
accelX = accel_x / 15000.0;
Serial.printf("X-axis acceleration is %0.2f\n", accelX);
accel_y_h = Wire.read();
accel_y_L = Wire.read();
accel_y = accel_y_h <<8 | accel_y_L;
accelY = accel_y / 16000.0;
Serial.printf("Y-axis acceleration is %0.2f\n", accelY);
accel_z_h = Wire.read();
accel_z_L = Wire.read();
accel_z = accel_z_h << 8 | accel_z_L;
accelZ = accel_z / 15250.0;
Serial.printf("Z-axis acceleration is %0.2f\n", accelZ);
accelTot = sqrt(pow(accelX,2)+pow(accelY,2)+pow(accelZ,2));
Serial.printf("Accel Total Value: %0.2f \n", accelTot);
if(!MPUfall)
{
MPUValue = accelTot;
MPUfall = (MPUValue > fall);
Serial.printf("MPU Value is %0.2f\n", MPUValue);
}
//Code for GPS
while (Serial1.available() > 0)
{
if (gps.encode(Serial1.read()))
{
displayInfo();
}
}
delay(1000);
}
void findAcceleration()
{
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission(false);
}
void displayInfo()
{
float lat,lon,alt;
uint8_t hr,mn,se,sat;
if (millis() - lastSerial >= SERIAL_PERIOD)
{
lastSerial = millis();
char buf[128];
if (gps.location.isValid() && gps.location.age() < MAX_GPS_AGE_MS)
{
lat = gps.location.lat();
lon = gps.location.lng();
alt = gps.altitude.meters();
hr = gps.time.hour();
mn = gps.time.minute();
se = gps.time.second();
sat = gps.satellites.value();
if(hr > 7)
{
hr = hr + UTC_offset;
}
else
{
hr = hr + 24 + UTC_offset;
}
Serial.printf("Time: %02i:%02i:%02i --- ",hr,mn,se);
Serial.printf("lat: %f, long: %f, alt: %f \n", lat,lon,alt);
if (gettingFix)
{
gettingFix = false;
unsigned long elapsed = millis() - startFix;
Serial.printlnf("%lu milliseconds to get GPS fix", elapsed);
}
display.clearDisplay();
display.setCursor(0,0);
display.printf("Time: %02i:%02i:%02i \n",hr,mn,se);
display.printf("lat %f \nlong %f \nalt %f\n", lat,lon,alt);
display.printf("satelites %i", sat);
display.display();
createEventPayload(lat, lon, alt, sat);
}
else
{
strcpy(buf, "no location");
if (!gettingFix)
{
gettingFix = true;
startFix = millis();
}
}
}
}
void createEventPayload(float jlat, float jlon, float jalt, int sat)
{
sprintf(buffer, "{\"lat\":%0.6f,\"lon\":%0.6f,\"ele\":%0.2f}", jlat, jlon, jalt);
}
void printValues()
{
Serial.printf("Temperature = %f\n", tempF);
Serial.print(bme.readTemperature());
Serial.println(" *F");
Serial.printf("Pressure = %f\n", inHg);
Serial.print(bme.readPressure());
Serial.println(" hPa");
Serial.printf("Humidity = %f\n", humidRH);
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.print("Distance: ");
Serial.print(distance);
Serial.println("cm");
Serial.printf("Moist: %i %%\n", soilMoisturePercent);
Serial.printf("Dust: %0.2f\n", dustSense);
Serial.println();
}
void adafruitPublish()
{
//Code for Adafruit.IO
if(intruder)
{
Trigger.publish(distance);
intruder = false;
}
if((millis()-lastPub > 30000))
{
if(mqtt.Update())
{
Serial.printf("Publishing %s\n", buffer);
GPS.publish(buffer);
Moist.publish(soilMoisturePercent);
Temp.publish(tempF);
Humid.publish(humidRH);
Dust.publish(dustSense);
Pressure.publish(inHg);
Satellites.publish(sat);
if(MPUfall)
{
FallSense.publish(MPUValue);
Serial.printf("MPU Fell %0.2f\n", MPUValue);
MPUfall = false;
MPUValue = 0.0;
}
}
lastPub = millis();
}
}
void MQTT_connect()
{
int8_t ret;
// Stop if already connected.
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000); // wait 5 seconds
}
Serial.println("MQTT Connected!");
// Ping MQTT Broker every 2 minutes to keep connection alive
if ((millis()-lastMQTT)>120000)
{
Serial.printf("Pinging MQTT \n");
if(! mqtt.ping()) {
Serial.printf("Disconnecting \n");
mqtt.disconnect();
}
lastMQTT = millis();
}
}
The article was first published in hackster, May 21, 2022
cr: https://www.hackster.io/stephanie-and-kareem/smart-farming-system-3ad87e
author: Team Stephanie and Kareem: Kareem Crum, Stephanie Perea