This is H2whoa An indoor plant watering and room monitoring system. How I put it all together.
Things used in this project
Hardware components
Story
This is H2whoa
An indoor plant watering and room monitoring system.
Here's what I used to put it all together.
BME280
Reads humidity, pressure, and, temperature
Measurements are either triggered by the user manually or performed automatically in regular intervals
The BME can be used for:
skin detection
Home automation control
Indoor navigation like going from one floor to another
In my project I'll be using it to read temperature, humidity, and barometric pressure
In general, a rising barometer means improving weather
In general, a falling barometer means worsening weather
When atmospheric pressure drops suddenly, this usually indicates that a storm is on its way.
When atmospheric pressure remains steady, there will likely be no immediate change in the weather
Moisture sensor
Uses the capacitive method to measure the moisture in the soil
Made from non-corrosive materials and outputs an analog signal and based on that reading we can gauge our soil moisture level
Dust sensor
Gauges the dust levels through a process using heat and light
Gives a good indication of the air quality in an environment by measuring the dust concentration
The unit must be Kept it upright to operate efficiently
The Grove air quality sensor
Monitors for harmful gases such as carbon monoxide, alcohol, formaldehyde and so on
Although it doesn’t output the presence of WHICH pollutant has been detected, it registers a reading indicating the presence of 1, some, or all, the monitored gases.
Water pump and relay
-The pump used for watering our plant requires more power than the Argon can supply directly, so a relay to step up to the pump requirement is used
Just like humans, for plants to grow and thrive, the environment of which it lives will prove the quality of life.
With the data collected from the chosen environmental sensors in this project, I'm able to then represent accurate, useful, information that helps make informed decisions concerning the ideal environment for the plant life.````
How I chose to represent my data is through an easy to read online visual dashboard. It provides updated information down to the minute.
OLED
Grove - OLED Display - I2c
In addition to the online dashboard, I've installed a Grove OLED display with sensor readings
Initially I wanted to make each reading displayed differently just for the sake of diversity. By doing that, my dashboard looked "cool" but it took more effort to discern what I was actually looking at and what any of it meant. I revised it to be more natural, when we look at our car dashboards the temperature, speed, and other gauges are mostly circular, a low side, high side, and typically we desire to be in between those same with the dashboard I've created.
Schematics
H2Whoa Schematic
H2Whoa Fritzing
代码
H2Whoa
C/C++
/*
* Project H2Whoa
* Description:
* Author:
* Date:
*/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "credentials.h"
#include "Air_Quality_Sensor.h"
TCPClient TheClient;
Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY);
Adafruit_MQTT_Publish bmeTemp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Ambient Temperature");
Adafruit_MQTT_Publish bmeHumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Humidity");
Adafruit_MQTT_Publish bmeAirPressure = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Air Pressure");
Adafruit_MQTT_Publish soilSaturation = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Soil Saturation");
Adafruit_MQTT_Publish dustParticulates = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Dust Particulates");
Adafruit_MQTT_Publish airQuality = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/Air Quality");
Adafruit_MQTT_Subscribe waterMe = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/H20");
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_BME280 bme;
bool status;
uint currentTime;
int onOrOff,ambientTemp;
const int relayPin = A5;
const int soilPin = A4;
const int dustPin = A3;
float soilReading;
float temperature;
float humidRH;
float pressPA;
float pressInhg;
uint last;
float inhg = .000295;
unsigned long duration;
unsigned long starttime;
unsigned long sampletime = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
AirQualitySensor sensor = (A2);
int quanAirValue;
int quality;
String DateTime, TimeOnly;
void setup() {
Serial.begin(9600);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)){
for(;;);
}
WiFi.connect();
while(WiFi.connecting()){
Serial.printf(".");
}
status = bme.begin(0x76);
if (sensor.init()) {
Serial.println("Sensor ready.");
}
else {
Serial.println("Sensor ERROR!");
}
display.display();
mqtt.subscribe(&waterMe);
pinMode(relayPin,OUTPUT);
pinMode(soilPin,INPUT);
pinMode(dustPin, INPUT);
Time.zone(-7);
Particle.syncTime();
}
void loop() {
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
displayOLED();
MQTT_connect();
if ((millis()-last)>120000) {
Serial.printf("Pinging MQTT \n");
if(! mqtt.ping()) {
Serial.printf("Disconnecting \n");
mqtt.disconnect();
}
last = millis();
}
currentTime = millis();
if((currentTime - last) > 1800000) {
readSoil();
if(mqtt.Update()){
soilSaturation.publish(soilReading);
}
last = millis();
}
currentTime = millis();
if((currentTime - last) > 30000) {
readTempF();
readHumidity();
readPressureInhg();
readDust();
readAirQuality();
if(mqtt.Update()){
bmeTemp.publish(temperature);
bmeHumidity.publish(humidRH);
bmeAirPressure.publish(pressInhg);
dustParticulates.publish(concentration);
airQuality.publish(quanAirValue);
}
last = millis();
}
Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(1000))) {
if (subscription == &waterMe) {
onOrOff = atoi((char *)waterMe.lastread);
if((currentTime - last) > 500) {
digitalWrite(relayPin, HIGH);
}
else {
digitalWrite(relayPin, LOW);
}
last = millis();
Serial.printf("Received %i from Adafruit.io feed H20 \n",onOrOff);
}
}
if(onOrOff){
digitalWrite(relayPin,HIGH);
}
else{
digitalWrite(relayPin,LOW);
}
}
float readTempF(){ // print temp every 60 seconds
float tempC;
tempC = bme.readTemperature();
temperature = map(tempC, 0.0, 100.0, 32.0, 212.0);
return(temperature);
}
float readHumidity() {
humidRH = bme.readHumidity();
return(humidRH);
}
float readPressureInhg() {
pressPA = bme.readPressure();
pressInhg = pressPA * inhg;
return (pressInhg);
}
float readSoil(){
soilReading = analogRead(soilPin);
if(soilReading >= 3000.0){
if((currentTime - last) > 500) {
digitalWrite(relayPin, HIGH);
}
else {
digitalWrite(relayPin, LOW);
}
last = millis();
}
Serial.printf("Soil Saturation %.01f \n", soilReading);
return (pressInhg);
}
float readDust(){
duration = pulseIn(dustPin,LOW);
lowpulseoccupancy = lowpulseoccupancy+duration;
ratio = lowpulseoccupancy/(sampletime*10.0);
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62;
Serial.printf("Dust Concentration %.01f \n",concentration);
lowpulseoccupancy = 0;
starttime = millis();
return(concentration);
}
int readAirQuality(){
quanAirValue = sensor.getValue();
quality = sensor.slope();
Serial.printf("Air Quality %i \n", quanAirValue);
if (quality == AirQualitySensor::FORCE_SIGNAL) {
Serial.printf("High pollution! Force signal active \n");
}
else if (quality == AirQualitySensor::HIGH_POLLUTION) {
Serial.printf("High pollution \n");
}
else if (quality == AirQualitySensor::LOW_POLLUTION) {
Serial.printf("Low pollution \n");
}
else if (quality == AirQualitySensor::FRESH_AIR) {
Serial.printf("Fresh air \n");
}
return (quanAirValue);
}
void displayOLED(void){
display.clearDisplay();
display.printf("Temperature %.01f \n",temperature);
display.printf("Humidity %.01f \n",humidRH);
display.printf("Air Pressure %.01f \n",pressInhg);
display.printf("Soil Moisture %.01f \n",soilReading);
display.printf("Dust Concentration %.01f \n",concentration);
if (quality == AirQualitySensor::FORCE_SIGNAL) {
display.printf("High pollution! Force signal active \n");
}
else if (quality == AirQualitySensor::HIGH_POLLUTION) {
display.printf("High pollution \n");
}
else if (quality == AirQualitySensor::LOW_POLLUTION) {
display.printf("Low pollution \n");
}
else if (quality == AirQualitySensor::FRESH_AIR) {
display.printf("Fresh air \n");
}
DateTime = Time.timeStr();
TimeOnly = DateTime.substring(11,19);
display.printf("%s, %s\n",DateTime.c_str(),TimeOnly.c_str());
display.display();
}
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.printf("%s\n",(char *)mqtt.connectErrorString(ret));
Serial.printf("Retrying MQTT connection in 5 seconds..\n");
mqtt.disconnect();
delay(5000); // wait 5 seconds
}
Serial.printf("MQTT Connected!\n");
}
The article was first published in hackster, November 11, 2021
cr: https://www.hackster.io/edward-ishman/h2whoa-130895
author: Edward Ishman