/*
* Project L14_04_PlantWater
* Description: Self watering planter
* Author: Carli Stringfellow
* Date: 04-20-2021
*/
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Air_Quality_Sensor.h"
#include "Adafruit_BME280.h"
#include "credentials.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_GFX.h"
#include "Math.h"
/************ Global State (you don't need to change this!) *** ***************/
// SYSTEM_MODE(SEMI_AUTOMATIC); //You need to comment out to get real time
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 waterButtonFeed = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/manualwater");
Adafruit_MQTT_Publish moistureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/soilmoisturelevel");
Adafruit_MQTT_Publish temperatureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/roomtemperature");
Adafruit_MQTT_Publish humidityFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/roomhumidity");
Adafruit_MQTT_Publish dustParticleFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/dustconcentration");
Adafruit_MQTT_Publish airQualityFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/indoorairquality");
// MQTT publish and subscribe to adafruit cloud (declarations)
unsigned long last;
unsigned long lastTime;
bool waterValue;
//Air pollution sensor (declarations)
AirQualitySensor airSensor(A0);
unsigned long lastTimeAir;
//Dust sensor (declarations)
const int DUSTPIN = A5;
unsigned long duration;
unsigned long startTime;
unsigned long sampleTime_ms = 2000;
unsigned long lowPulseOccupancy = 0;
float ratio = 0;
int concentration = 0;
//Capacitive soil moisture sensor v1.2 (declarations)
int soilMoisture;
const int SOILPIN = A4;
//Water pump (declarations)
const int WATERPIN = A2;
int pumpTimer;
//OLED (declarations)
const int OLED_RESET = D4;
Adafruit_SSD1306 display(OLED_RESET);
int rot = 2;
//Timestamp (declarations)
String DateTime;
String TimeOnly;
char currentDateTime[25], currentTime[9];
//BME (declarations)
const int chipSelect = 4;
float tempF;
float humidity;
Adafruit_BME280 bme;
void setup() {
Serial.begin(9600);
bme.begin(0x76); // Turns on bme sensor
while (!Serial);
delay(100);
pinMode(WATERPIN, OUTPUT);
pinMode(SOILPIN,INPUT);
pinMode(DUSTPIN,INPUT);
pinMode(A0, INPUT);
startTime = millis(); //Checks current time
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display ();
delay(1000);
display.clearDisplay();
display.setRotation(rot);
//Sets the timezone to mountain daylight time
Time.zone(-6);
Particle.syncTime();
Serial.printf("Connecting to Internet \n");
WiFi.connect();
while(WiFi.connecting()) {
Serial.printf(".");
delay(100);
}
Serial.printf("\n Connected!!!!!! \n");
// Setup MQTT subscription for onoff feed.
mqtt.subscribe(& waterButtonFeed);
if (airSensor.init()) {
Serial.println("Air Sensor ready.");
}
else {
Serial.println("Air Sensor ERROR!");
}
}
//THE VOIIIIIID LOOOOOOOP
void loop() {
MQTT_connect(); //Connects to wifi
timeAndDisplay(); // Displays BME data and time
dustSensor(); //Detects dust particles
airQualityCheck(); //Checks air quality
cloudData(); //Pings internet and publishes/subscribes to adafruit cloud
}
// 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!");
}
//Calls for current time and displays time and other readings:
void timeAndDisplay() {
DateTime = Time.timeStr();
TimeOnly = DateTime.substring(11,19);
// Converts String to char arrays
DateTime.toCharArray(currentDateTime, 25);
TimeOnly.toCharArray(currentTime,9);
display.display();
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
// CAN BE SEEN ON OLED SCREEN
tempF = 1.8*(bme.readTemperature())+32; // Converts celsius to fahrenheit
display.printf("Tempurature: %0.1f\n", tempF);
// Serial.printf("Tempurature is %0.1f\n" ,tempF);
humidity = bme.readHumidity(); // Displays humidity
display.printf("Humidity: %0.1f\n", humidity);
// Serial.printf("Humidity is %0.1f\n" ,humidRH);
display.printf("Dust Parts: %i\n", concentration);
// Serial.printf("Dust Particles: %i\n", concentration);
soilMoisture = analogRead(SOILPIN);
Serial.printf("Soil Moisture %i \n", soilMoisture);
display.printf("Soil Moisture: %i\n", soilMoisture); // Displays soil moisture
display.printf("%s\n", currentTime); // Displays current MDT
display.display();
}
//SUBSCRIPTIONS AND PUBLISHED READINGS TO ADAFRUIT CLOUD MANUAL WATER BUTTON
void cloudData() {
// Ping MQTT Broker every 2 minutes to keep connection alive
if ((millis()-last)>120000) {
Serial.printf("Pinging MQTT \n");
if(! mqtt.ping()) {
Serial.printf("Disconnecting \n");
mqtt.disconnect();
}
last = millis();
}
// This is our 'wait for incoming subscription packets' busy subloop
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(1000))) {
if (subscription == &waterButtonFeed) {
waterValue = atoi((char *)waterButtonFeed.lastread);
Serial.printf("Water Value %i \n", waterValue);
if (waterValue == 1) { //****MANUAL WATER PUMP****
digitalWrite(WATERPIN,HIGH);
Serial.printf("Pump is ON");
delay(900);
digitalWrite(WATERPIN,LOW);
}
}
}
if((millis()-lastTime > 30000)) { // PUBLISHES TO CLOUD
if(mqtt.Update()) {
moistureFeed.publish(soilMoisture);
Serial.printf("Publishing Moisture %i\n", soilMoisture);
temperatureFeed.publish(tempF);
Serial.printf("Publishing Temp %0.1f\n", tempF);
humidityFeed.publish(humidity);
Serial.printf("Publishing Humidity %0.1f\n", humidity);
dustParticleFeed.publish(concentration);
Serial.printf("Publishing Dust %i\n", concentration);
airQualityFeed.publish(airSensor.getValue());
Serial.printf("Publishing Air %i\n", airSensor.getValue() );
}
lastTime = millis();
}
waterPump();
}
//Sets up water pump
void waterPump() {
if(soilMoisture > 2700) {
if ((millis()-pumpTimer)>30000) {
digitalWrite(WATERPIN,HIGH);
Serial.printf("Pump is ON \n");
delay(700);
digitalWrite(WATERPIN,LOW);
Serial.printf("Pump is OFF \n");
pumpTimer = millis();
}
}
}
//Dust detector
void dustSensor() {
duration = pulseIn(DUSTPIN, LOW);
lowPulseOccupancy = lowPulseOccupancy+duration;
if ((millis()-startTime) > sampleTime_ms) {
ratio = lowPulseOccupancy/(sampleTime_ms*10.0); // Integer percentage 0=>100
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
Serial.print(lowPulseOccupancy);
Serial.print(",");
Serial.print(ratio);
Serial.print(",");
Serial.println(concentration);
lowPulseOccupancy = 0;
startTime = millis();
}
}
// Checks air quality and displays whether it is high or low
void airQualityCheck() {
int quality = airSensor.slope();
display.display();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw WHITE text
display.setCursor(29,56); // Start at bootom-left corner
Serial.print("Air Sensor value: ");
Serial.printf("%i\n", airSensor.getValue());
if((millis()-lastTimeAir > 5000)) {
if (quality == AirQualitySensor::FORCE_SIGNAL) {
Serial.printf("High pollution! Force signal active.\n");
display.printf("High Pollution!");
}
else if (quality == AirQualitySensor::HIGH_POLLUTION) {
Serial.printf("High pollution!\n");
display.printf("High Pollution!");
}
else if (quality == AirQualitySensor::LOW_POLLUTION) {
Serial.printf("Low pollution!\n");
display.printf("Low Pollution!");
}
else if (quality == AirQualitySensor::FRESH_AIR) {
Serial.printf("Fresh air.\n");
display.printf("Fresh Air!");
}
display.display();
lastTimeAir = millis();
}
}
Comments
Please log in or sign up to comment.