/*
* Project: Automated Growth Chamber
* Description: This program is designed to collect data from several sensors,
* display the data to an OLED display, publish the data to the Adafruit IO
* dashboard, and automatically water a plant based upon moisture readings.
* Author: Saige Martinez
* Date: November 12, 2020
*/
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "config.h"
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "Particle.h"
#include "neopixel.h"
#include "Air_Quality_Sensor.h"
// Create an BME280 class.
Adafruit_BME280 bme;
// // Setup the SSD1306 display class by passing in the reset pin.
const int OLED_RESET = D4;
Adafruit_SSD1306 display(OLED_RESET);
// Set the Adafruit_Neopixel class by passing it the pixel count, pin, and type.
const int PIXEL_PIN = D8;
const int PIXEL_COUNT = 4;
#define PIXEL_TYPE WS2812B
Adafruit_NeoPixel pixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
// Set the AirQualitySensor class by passing it pin.
const int AIR_PIN = A0;
AirQualitySensor air(AIR_PIN);
// Create an TCPClient class to connect to the MQTT server.
TCPClient client;
// Setup the MQTT client class by passing in the TCP client, MQTT server, and login details.
Adafruit_MQTT_SPARK mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
// Feeds
Adafruit_MQTT_Publish temperature = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperature");
Adafruit_MQTT_Publish humidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humidity");
Adafruit_MQTT_Publish pressure = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/pressure");
Adafruit_MQTT_Publish moisture = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/soil moisture");
Adafruit_MQTT_Publish particulate = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/particulate");
Adafruit_MQTT_Publish airQuality = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/air quality");
Adafruit_MQTT_Subscribe pumpSwitch = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/pump");
Adafruit_MQTT_Subscribe lightSwitch = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/pixels");
// Declare variables here.
const int PUMP_PIN = D9;
const int MOISTURE_PIN = A5;
int moistureReading;
int moistureMapping;
int last = 0;
const int DUST_PIN = D10;
unsigned long duration;
unsigned long startTime;
unsigned long sampleTime = 30000;
unsigned long lowPulseOccupancy = 0;
float ratio = 0;
float concentration = 0;
int airQualityReading;
int airQualityMapping;
void setup() {
Serial.begin(9600);
bme.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
pixel.begin();
pixel.show();
// pixel.setBrightness(65);
pinMode(PUMP_PIN, OUTPUT);
pinMode(MOISTURE_PIN, INPUT);
pinMode(DUST_PIN, INPUT);
pinMode(AIR_PIN, INPUT);
air.init();
startTime = millis();
mqtt.subscribe(&pumpSwitch);
mqtt.subscribe(&lightSwitch);
}
void loop() {
connectMQTT();
moistureReading = analogRead(MOISTURE_PIN);
moistureMapping = map(moistureReading, 0, 4095, 100, 0);
airQualityReading = air.getValue();
airQualityMapping = map(airQualityReading, 0, 1000, 0, 500);
getParticulates();
displayData();
publishData();
subscribeData();
turnOnPump();
}
void connectMQTT() {
/*
* 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.
*/
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 getParticulates() {
duration = pulseIn(DUST_PIN, LOW);
lowPulseOccupancy = lowPulseOccupancy + duration;
if((millis()-startTime) > sampleTime) {
ratio = lowPulseOccupancy / (sampleTime * 10.0);
concentration = 1.1 * pow(ratio, 3) - 3.8 * pow(ratio, 2) + 520 * ratio + 0.62;
lowPulseOccupancy = 0;
startTime = millis();
}
}
void displayData() {
/*
* Function to print data to the OLED display.
*/
display.clearDisplay();
display.setCursor(0, 0);
display.setTextColor(WHITE);
display.println("Environmental Reading");
display.printlnf("Temperature: %0.1f %cC", bme.readTemperature(), (char)247);
display.printlnf("Humidity: %0.1f%%", bme.readHumidity());
display.printlnf("Pressure: %0.0f hPa", bme.readPressure()/100.0);
display.printlnf("Moisture: %i%%", moistureMapping);
display.printlnf("PM Level: %0.0f p/F", concentration);
display.printlnf("Air Quality: %i AQI", airQualityMapping);
display.display();
}
void publishData() {
/*
* Function to publish data to Adafruit IO.
*/
if(millis()-last > 30000) {
if(mqtt.Update()) {
temperature.publish(bme.readTemperature());
humidity.publish(bme.readHumidity());
pressure.publish(bme.readPressure()/100.0);
moisture.publish(moistureMapping);
particulate.publish(concentration);
airQuality.publish(airQualityMapping);
}
last = millis();
}
}
void subscribeData() {
/*
* Function to subscribe to Adafruit IO.
* This is our 'wait for incoming subscription packets' busy subloop,
* try to spend your time here.
*/
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(5000))) {
// Check if it is the pump feed.
if(subscription == &pumpSwitch) {
if (strcmp((char *)pumpSwitch.lastread, "OFF") == 0) {
digitalWrite(PUMP_PIN, LOW);
}
if (strcmp((char *)pumpSwitch.lastread, "ON") == 0) {
digitalWrite(PUMP_PIN, HIGH);
}
}
// Check if it is the light feed.
if(subscription == &lightSwitch) {
if (strcmp((char *)lightSwitch.lastread, "OFF") == 0) {
for(int i=0; i<4; i++) {
pixel.setPixelColor(i, 0, 0, 0);
pixel.show();
}
}
if (strcmp((char *)lightSwitch.lastread, "ON") == 0) {
for(int i=0; i<4; i++) {
pixel.setPixelColor(i, 255, 0, 51);
pixel.show();
}
}
}
}
}
void turnOnPump() {
/*
* Function to turn on water pump when mositure reading
* is less than 30%.
*/
if(moistureMapping < 30) {
digitalWrite(PUMP_PIN, HIGH);
delay(1000);
digitalWrite(PUMP_PIN, LOW);
}
else {
digitalWrite(PUMP_PIN, LOW);
}
}
Comments