Hardware components | ||||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
| |||||
Hand tools and fabrication machines | ||||||
![]() |
|
My first attempt to design, program and build a self watering planter.
This device has a soil moisture sensor to detect when the plant needs to be watered. It also has an air quality sensor, a dust sensor, temperature, humidity and atmospheric pressure. With all collected data being displayed on a OLED. In addition the data is also sent to the cloud, where it is saved. I used io.adafruit.com for cloud storage. this allowed me to view the data remotely. grafting it over any selected time frame (for the project it only displays the last day)
Depending on the reading from the soil moisture sensor, a pump can automatically water the plant, or from the cloud dashboard you are able to manually water the plant by clicking a button.
For the processor I used a particle argon, and wrote our code in C++ using visual studio code. I wrote the code for each sensor, then for the pump. Once I was collecting data I began writing the code to send it to the cloud, the OLED and the serial monitor.
I then choose to 3D print a stand to hold all of the electronics and mount the display on top. I had hoped for it to stand on its own over a water reservoir while holding the flower pot on top. My design turn out to be to flimsy. If I was to redo this I would of made the supports stronger. the sides are mesh so that I could screw all of the components to the side of the enclosure
/*
* Project L14_02
* Description: moisture sensor
* Author: Benjamin hansen
* Date: 08/10/2020
*/
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT/Adafruit_MQTT.h>
#include <Adafruit_MQTT/Adafruit_MQTT_SPARK.h>
#include <Adafruit_MQTT/Adafruit_MQTT.h>
/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883 // use 8883 for SSL
#define AIO_USERNAME "BenjaKH"
#define AIO_KEY "aio_KKGV98C9rUd8ZHvj2OGgx3KihYMz"
/************ Global State (you don't need to change this!) *** ***************/
TCPClient TheClient;
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY);
/****************************** Feeds ***************************************/
// Setup Feeds to publish or subscribe
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
// Adafruit_MQTT_Subscribe GraftLineFeed = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/graftineFeed");
Adafruit_MQTT_Publish AtmosphericPressureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Atmospheric_Pressure_Feed");
Adafruit_MQTT_Publish HumidityFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Humidity_Feed");
Adafruit_MQTT_Publish TematureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Temature_Feed");
Adafruit_MQTT_Publish MoistureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Moisture_Feed");
Adafruit_MQTT_Publish AirQualitySensorFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Air_Quality_Sensor_Feed");
Adafruit_MQTT_Publish DustSensorFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Dust_Sensor_Feed");
// Adafruit_MQTT_Publish variable1 = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/variable1"); //this is the feed template
Adafruit_MQTT_Subscribe WaterPlantButton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/WaterPlantButton");
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Air_Quality_Sensor.h>
#include <math.h>
#define BME_SCK D4
#define BME_MISO D3
#define BME_MOSI D2
#define BME_CS D5
#define SEALEVELPRESSURE_HPA (1013.25)
#define OLED_RESET D4
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_BME280 bme;
String DateTime, TimeOnly;
AirQualitySensor airSensor(A2);
unsigned long last;
int mValue, count, currentTime, lastSecond, variable1, lastTime, quality;
const int MoistureSensor = A1;
int Pump = D6;
unsigned long delayTime;
float humidRH, pressPA, tempC, tempF, hpa, inHg;
float value;
//dust sensor variables
int dustSensor = A0;
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 500;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
void setup() {
Serial.begin(9600);
int quality = airSensor.slope();
mqtt.subscribe(&WaterPlantButton);
pinMode(dustSensor,INPUT);
pinMode(MoistureSensor, INPUT);
pinMode(Pump, OUTPUT);
sync_my_time();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128x64)
display.display(); // show splashscreen
delay(2000);
display.clearDisplay();
Serial.print("Hello");
BMEsetup();
initAirSensor();
}
void loop() {
currentTime = millis();
DateTime = Time.timeStr();
TimeOnly = DateTime.substring(11, 19);
if((currentTime - lastSecond) >1000){
printValues();
displayValues();
lastSecond = millis();
}
BMEloop();
mValueFunction();
MQTT_connect();
variable1 = rand() % 100;
MQTTping();
adafruitPublishing();
WaterPlantButtonFunction();
ifSoilDryWater();
dustSensorLoop();
}
void sync_my_time() {
String DateTime, TimeOnly;
Time.zone (-6);
Particle.syncTime();
waitUntil(Particle.syncTimeDone);
}
void BMEsetup(){
while (!Serial); // time to get serial running
Serial.println(F("BME280 test"));
unsigned status;
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin();
if (!status)
{
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
Serial.print("SensorID was: 0x");
Serial.println(bme.sensorID(), 16);
Serial.print(" ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
Serial.print(" ID of 0x56-0x58 represents a BMP 280,\n");
Serial.print(" ID of 0x60 represents a BME 280.\n");
Serial.print(" ID of 0x61 represents a BME 680.\n");
while (1)
;
}
}
void printValues(){
Serial.println(TimeOnly);
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.print("Moisture level= ");
Serial.print(mValue);
Serial.println(" ");
AirSensorPrint();
Serial.print("Dust particle Ratio is ");
Serial.print(concentration);
Serial.println(" ");
Serial.println();
}
float CtoF(float IN) {
return (IN * 1.8) + 32;
}
float PressCon(float P){
return (0.03 * P);
}
void displayValues(void) {
static int t = 0;
// delay(2000);
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(0,0); // Start at top-left corner
display.println(TimeOnly);
display.setCursor(0,16);
if (t == 0){
display.printf("Atomspheric pressure is %0.2f inches mercury. \n \n", inHg);
}
if (t == 1){
display.printf("Humidity is %0.2f percent. \n \n", humidRH);
}
if (t == 2){
display.printf("Temperature right now is %0.2f , F. \n \n", tempF);
}
if (t == 3){
display.printf("Moisure value is %i. \n \n", mValue);
}
if (t == 4){
AirSensorDisplay();
}
if (t == 5){
display.printf("The Particual ratio is %i, \n \n", concentration);
}
display.display();
t++;
if (t > 5){
t = 0;
}
}
void BMEloop(){
pressPA = bme.readPressure() / 100.0F;
inHg = PressCon(pressPA);
humidRH = bme.readHumidity();
tempC = bme.readTemperature();
tempF = CtoF(tempC);
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
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!");
}
void adafruitPublishing(){
if((millis()-lastTime > 120000)) {
if(mqtt.Update()) {
AtmosphericPressureFeed.publish(inHg);
Serial.printf("Publishing %0.2f \n", inHg);
HumidityFeed.publish(humidRH);
TematureFeed.publish(tempF);
MoistureFeed.publish(mValue);
AirQualitySensorFeed.publish(airSensor.getValue());
DustSensorFeed.publish(concentration);
}
lastTime = millis();
}
}
void MQTTping(){
if ((millis()-last)>120000) {
Serial.printf("Pinging MQTT \n");
if(! mqtt.ping()) {
Serial.printf("Disconnecting \n");
mqtt.disconnect();
}
last = millis();
}
}
void waterPlant(){
Serial.println("Plant is being watered");
digitalWrite(Pump, HIGH);
delay(1000);
digitalWrite(Pump, LOW);
delay(1000);
}
void WaterPlantButtonFunction(){
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(10000))) {
if (subscription == &WaterPlantButton) {
value = atof((char *)WaterPlantButton.lastread);
if (value == 1){
waterPlant();
}
}
}
}
void ifSoilDryWater(){
if (mValue > 2500){
waterPlant();
}
}
void mValueFunction(){
mValue = analogRead(MoistureSensor);
}
void initAirSensor(){
Serial.println("Waiting sensor to init...");
delay(20000);
if (airSensor.init()) {
Serial.println("Sensor ready.");
}
else {
Serial.println("Sensor ERROR!");
}
}
void AirSensorPrint(){
Serial.print("Air quality value: ");
Serial.println(airSensor.getValue());
if (quality == AirQualitySensor::FORCE_SIGNAL) {
Serial.println("High pollution! Force signal active.");
}
else if (quality == AirQualitySensor::HIGH_POLLUTION) {
Serial.println("High pollution!");
}
else if (quality == AirQualitySensor::LOW_POLLUTION) {
Serial.println("Low pollution!");
}
else if (quality == AirQualitySensor::FRESH_AIR) {
Serial.println("Fresh air.");
}
}
void AirSensorDisplay(){
display.print("Air quality value: ");
display.println(airSensor.getValue());
if (quality == AirQualitySensor::FORCE_SIGNAL) {
display.println("High pollution! Force signal active.");
}
else if (quality == AirQualitySensor::HIGH_POLLUTION) {
display.println("High pollution!");
}
else if (quality == AirQualitySensor::LOW_POLLUTION) {
display.println("Low pollution!");
}
else if (quality == AirQualitySensor::FRESH_AIR) {
display.println("Fresh air.");
}
}
void dustSensorLoop(){
Comments