Meng-Yun Tsai

From Medien Wiki

Project : The Air Between Us

Initial Idea

 

-

Project Concept

-

Brainstorming

https://www.figma.com/board/liuTtexNHdKw09Ce0443xg/The-Plant-Plant_Moodboard?node-id=0-1&t=8V8UNVewNwZUOFky-1

Sketches

 

Moodboard

 

Preparation ( 2 Isolated Plant Systems)

MS Media



Recipe:

1 Liter Water:

Murashige 4.5 g

Gelrite 5 g

D(+) Saccharose 20 g (sugar)


Sterilizing & Transplanting

-

Video:

Images/291123 cleaningHelleborus.mov

Images/051224 observe Helleborus.mov

Plants Observation

-

Prototype

Electronics / Circuits

-

Programming

Code:

/*
  Project: The Plant Plant - The Air Between Us
  Integration and Conversation between 2 isolated plant systems
  By using Microcontroller, sensors and IoT platform (cloud)
  --
  Board: ESP32 Development Board
  Component: MQ-2 Gas Sensor
             DHT22 Temperature & Humidity Sensor
             Alphanumerisches LCD 16x2, blau
  --
  Note: After the MQ-2 sensor is powered on, it needs to be preheated for 
  at least 3 minute before stable measurement readings can be obtained. 
  It is normal for the sensor to generate heat during operation due to 
  the presence of a heating wire inside.

*/

//add libraries
#include <Arduino.h>
#include <Adafruit_Sensor.h>     // for DHT22
#include <DHT.h>
#include <DHT_U.h>    
#include <WiFi.h>                // for connecting Wifi   
#include "esp_wpa2.h"            //wpa2 library for connections to Enterprise networks
#include <ThingSpeak.h>          // for publishing Sensor Readings to Thingspeak
#include <Wire.h>                // for getting the LCD Address
#include <LiquidCrystal_I2C.h>   // for LCD

/* Set up: DHT22 */
#define DHTTYPE DHT22   // sensor version, we are using DHT22
#define DHT22_PIN1  4 // Group01 pin GPIO4
#define DHT22_PIN2  15 // Group02 pin GPIO15 
#define DHT22_PIN3  0 // Group03 pin GPIO0
//Create sensors called "dht..."
DHT_Unified dht01(DHT22_PIN1, DHTTYPE); 
DHT_Unified dht02(DHT22_PIN2, DHTTYPE); 
DHT_Unified dht03(DHT22_PIN3, DHTTYPE); 
int delayMS = 1500; // add delay after each reading

/* Set up: MQ2 */
// Define the pin numbers for the Gas Sensor
#define MQ2_PIN1  34  // Group01 pin GPIO34
#define MQ2_PIN2  35  // Group02 pin GPIO35
#define MQ2_PIN3  32  // Group03 pin GPIO32

/* Set up: Thingspeak */
// due to the privacy of the account, won't show the real numbers
unsigned long ChannelNumber1 = XXXXXXX;     //Insert Thingspeak Channel's number 
unsigned long ChannelNumber2 = XXXXXXX;     //Insert 2nd Thingspeak Channel's number 
const char *WriteAPIkey1="XXXXXXXXXXXXXXXX";   // Thingspeak Official Channel API Key
const char *WriteAPIkey2="XXXXXXXXXXXXXXXX";   // 2nd Thingspeak Official Channel API Key

/* Set up: Eduroam Wifi */
WiFiClient client;

byte mac[6];
const char* host = "arduino.clanweb.eu";     //webserver test
String url = "/eduroam/data.php";            //URL to target PHP file test
#define EAP_ANONYMOUS_IDENTITY "XXXXXX@uni-weimar.de" //anonymous@example.com, or you can use also nickname@example.com
#define EAP_IDENTITY "XXXXXX" //nickname@example.com,at some organizations should work nickname only without realm, but it is not recommended
#define EAP_PASSWORD "XXXXXX" //password for eduroam account
//SSID NAME
const char* ssid = "eduroam"; // eduroam SSID

/* Set up: LCD */
// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
// set LCD address, number of columns and rows
// if don't know the display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows); 
// set up display texts 
String messageStatic = "Our Dialogue";
String messageScrolling;
// A string variable used to store accumulated ASCII conversations
String dialogue = ""; 
// for counting characters from ASCII codes 
int charCount = 0;     

/* Function: Scrolling Texts */
// The function accepts the following arguments:
// row: row number where the text will be displayed
// message: message to scroll
// delayTime: delay between each character shifting
// lcdColumns: number of columns of your LCD
void scrollingText(int row, String message, int delayTime, int lcdColumns) {
  for (int i=0; i < lcdColumns; i++) {
    message = " " + message;  
  } 
  message = message + " "; 
  for (int pos = 0; pos < message.length(); pos++) {
    lcd.setCursor(0, row);
    lcd.print(message.substring(pos, pos + lcdColumns));
    delay(delayTime);
  }
}

/* Functions: Group01 Flowers */
void Group01(){
  // Delay between measurements
  delay(delayMS);   

  //Reading DHT22
  // Get access to sensor event through custom sensor event type
  sensors_event_t event;

  // get temperature event (by reference, not by copy) and print its value.
  // "event" is  - after this - filled with information from the sensor.
  dht01.temperature().getEvent(&event);
  if (isnan(event.temperature))
  {
    Serial.println(F("Error reading temperature!"));
  }
  else
  {
    Serial.print(F("G1 Temperature: "));
    Serial.print(event.temperature);
    Serial.println(F("°C"));
    ThingSpeak.setField(2, event.temperature); // write to Thingspeak Channel Field 2
  }

  // get humidity event (by reference, not by copy) and print its value.
  // "event" is  - after this - filled with information from the sensor.
  dht01.humidity().getEvent(&event);
  if (isnan(event.relative_humidity))
  {
    Serial.println(F("Error reading humidity!"));
  }
  else
  {
    Serial.print(F("G1 Humidity: "));
    Serial.print(event.relative_humidity);
    Serial.println(F("%"));
    ThingSpeak.setField(3, event.relative_humidity); // write to Thingspeak Channel Field 3
  }

  //Reading MQ2 
  int mq2g1V = analogRead(MQ2_PIN1);
  Serial.print("G1 MQ2 Analog output: ");
  Serial.println(mq2g1V);
  Serial.println(" ------------------ ");
  delay(1000);
  ThingSpeak.setField(1, mq2g1V); // write to Thingspeak Channel Field 1
}

/* Functions: Group02 Sundew */
void Group02(){
  delay(delayMS);   

  //Reading DHT22
  sensors_event_t event;

  dht02.temperature().getEvent(&event);
  if (isnan(event.temperature))
  {
    Serial.println(F("Error reading temperature!"));
  }
  else
  {
    Serial.print(F("G2 Temperature: "));
    Serial.print(event.temperature);
    Serial.println(F("°C"));
    ThingSpeak.setField(5, event.temperature); // write to Thingspeak Channel Field 5
  }

  dht02.humidity().getEvent(&event);
  if (isnan(event.relative_humidity))
  {
    Serial.println(F("Error reading humidity!"));
  }
  else
  {
    Serial.print(F("G2 Humidity: "));
    Serial.print(event.relative_humidity);
    Serial.println(F("%"));
    ThingSpeak.setField(6, event.relative_humidity); // write to Thingspeak Channel Field 6
  }

  //Reading MQ2 
  int mq2g2V = analogRead(MQ2_PIN2);
  Serial.print("G2 MQ2 Analog output: ");
  Serial.println(mq2g2V);
  Serial.println(" ------------------ ");
  delay(1000);
  ThingSpeak.setField(4, mq2g2V); // write to Thingspeak Channel Field 4
}

/* Functions: Group03 Integration */
void Group03(){
  delay(delayMS);   

  //Reading DHT22
  sensors_event_t event;

  dht03.temperature().getEvent(&event);
  if (isnan(event.temperature))
  {
    Serial.println(F("Error reading temperature!"));
  }
  else
  {
    Serial.print(F("G3 Temperature: "));
    Serial.print(event.temperature);
    Serial.println(F("°C"));
    ThingSpeak.setField(7, event.temperature); // write to Thingspeak Channel Field 7
    
  }

  dht03.humidity().getEvent(&event);
  if (isnan(event.relative_humidity))
  {
    Serial.println(F("Error reading humidity!"));
  }
  else
  {
    Serial.print(F("G3 Humidity: "));
    Serial.print(event.relative_humidity);
    Serial.println(F("%"));
    Serial.println(" ------------------ ");
    ThingSpeak.setField(8, event.relative_humidity); // write to Thingspeak Channel Field 8
    
  }

}

void Group03_MQ2(){
  //Reading MQ2 
  int mq2g3V = analogRead(MQ2_PIN3);
  Serial.print("G3 MQ2 Analog output: ");
  Serial.println(mq2g3V);
  delay(500);
  ThingSpeak.writeField(ChannelNumber2, 1, mq2g3V, WriteAPIkey2);

  // LCD messages  
  // convert MQ-2's value to ASCII code
  int ascii_value = map(mq2g3V, 200, 800, 65, 122);
  char ascii_char = (char)ascii_value;

  // a new character is added to the string (the previous one is kept)
  dialogue += ascii_char ;
  charCount++; // accumulated character count +1

  // Try using spaces to create a variation in sentence length for a more natural dialogue effect.
  // when the accumulated character count exceeds 7, insert a space randomly
  if (charCount > 7) {
    // if the count exceeds 15, force to insert a space 
    if (random(0, 2) == 1 || charCount >= 15) { 
      dialogue += " ";
      charCount = 0; // after inserting a space, reset the count
    }
  }
  // if the string length exceeds the LCD limit (32 characters)
  if (dialogue.length() > 32) { 
    dialogue = dialogue.substring(1); // remove the oldest character
  } 
  // print scrolling message
  lcd.setCursor(0, 1);
  messageScrolling = dialogue.substring(0, 16);
  scrollingText(1, messageScrolling, 350, lcdColumns);
}


void setup()
{
  // initialize serial communication
  Serial.begin(9600); 

  // connect or reconnect to wifi
  WiFi.disconnect(true); //disconnect from WiFi to set new WiFi connection
  WiFi.mode(WIFI_STA); //init wifi mode
  
  // start wifi connection with eduroam
  // WITHOUT CERTIFICATE - WORKING WITH EXCEPTION ON RADIUS SERVER
  WiFi.begin(ssid, WPA2_AUTH_PEAP, EAP_ANONYMOUS_IDENTITY, EAP_IDENTITY, EAP_PASSWORD); 
  
  // check if wifi connected
  // continue after while loop finished
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(F("."));
    }
    Serial.println("");
    Serial.println(F("WiFi is connected!"));
    Serial.println(" ");
  
  // initialize DHT22
  dht01.begin(); 
  dht02.begin(); 
  dht03.begin(); 
  
  // initialize ThingSpeak
  ThingSpeak.begin(client);   

  // initialize LCD
  lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();            

}

void loop()
{
  yield(); // buffer ESP - stuff

// show LCD
  lcd.clear();
  // set cursor to position (column and row)
  lcd.setCursor(2, 0);
  // print static message
  lcd.print(messageStatic);

// Execute functions of 3 groups
  Group03_MQ2();
  Group03();
  delay(delayMS);

  Group01();
  delay(delayMS);

  Group02();
  delay(delayMS);


  // Write to ThingSpeak.
  int x = ThingSpeak.writeFields(ChannelNumber1, WriteAPIkey1);

  if(x == 200){
     Serial.println("Channel update successful.");
   }else{
     Serial.println("Problem updating channel. HTTP error code " + String(x));
   }
   delay(15000);
}

Data Visualization

ThingSpeak Screenshots: sensors data observation

Winterwerkschau (Exhibition)

-photos-

Technical Riders

-

References

ESP32 with DHT22 Temperature and Humidity Sensor

The Plant Plant - GitHub Repo

https://randomnerdtutorials.com/esp32-dht11-dht22-temperature-humidity-sensor-arduino-ide/

ESP32 with MQ-2 Gas Sensor

https://docs.sunfounder.com/projects/umsk/en/latest/03_esp32/esp32_lesson04_mq2.html

ESP32 Publish Sensor Readings to ThingSpeak (Wi-Fi)

https://randomnerdtutorials.com/esp32-thingspeak-publish-arduino/#multiple

ESP32 with I2C LCD (Liquid Crystal Display)

https://randomnerdtutorials.com/esp32-esp8266-i2c-lcd-arduino-ide/

https://zhillan-arf.medium.com/getting-lcd-displays-to-work-with-esp32-e7fe8016bffd