Meng-Yun Tsai: Difference between revisions

From Medien Wiki
Line 62: Line 62:


=== Programming ===
=== Programming ===
Code
Code:<syntaxhighlight lang="arduino">
/*
  Project: The Plant Plant - The Air Between Us
  Intergration 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  15  // Group01 pin GPIO15
#define DHT22_PIN2  0  // Group02 pin GPIO0
#define DHT22_PIN3  4  // Group03 pin GPIO4
//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 Channe's number
unsigned long ChannelNumber2 = XXXXXXX;    //Insert 2nd Thingspeak Channe'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 "meng-yun.tsai@uni-weimar.de" //anonymous@example.com, or you can use also nickname@example.com
#define EAP_IDENTITY "daro6502" //nickname@example.com,at some organizations should work nickname only without realm, but it is not recommended
#define EAP_PASSWORD "Tuniman86704_Y" //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 you don't know your 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 letters from Ascii code
int charCount = 0;   
 
/* Function: Scrolling Texts */
// The function acepts 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 Intergration */
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 Display 
  // convert MQ-2's value to ASCII code
  int ascii_value = map(mq2g3V, 1000, 2500, 34, 126);
  char ascii_char = (char)ascii_value;
 
  // a new character is added to the string (the previous one is kept)
  dialogue += ascii_char ;
  charCount++; // a ccumulated 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 display 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
 
// LCD Display
  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);
}
</syntaxhighlight>


== Winterwerkschau (Exhibition) ==
== Winterwerkschau (Exhibition) ==

Revision as of 21:33, 30 January 2025

Project : The Air Between Us

Inspiration

-

Initial Idea

The Plant Plant Initial Idea.png

Project Concept

-

Brainstorming

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

Sketches

Moodboard

The Plant Plant Moodboard.png

Preparation ( 2 Isolated Plant Systems)

MS Media

The Plant Plant Preparation MS Medium.png

Agar-agar cultivation describe blah blah...

(Flowers - Plastic Bag - without sugar

Sundew - Glass Jar - with sugar)



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

Installation

-

Electronics / Circuits

-

Programming

Code:

/*
  Project: The Plant Plant - The Air Between Us
  Intergration 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  15  // Group01 pin GPIO15 
#define DHT22_PIN2  0   // Group02 pin GPIO0 
#define DHT22_PIN3  4   // Group03 pin GPIO4
//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 Channe's number 
unsigned long ChannelNumber2 = XXXXXXX;     //Insert 2nd Thingspeak Channe'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 "meng-yun.tsai@uni-weimar.de" //anonymous@example.com, or you can use also nickname@example.com
#define EAP_IDENTITY "daro6502" //nickname@example.com,at some organizations should work nickname only without realm, but it is not recommended
#define EAP_PASSWORD "Tuniman86704_Y" //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 you don't know your 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 letters from Ascii code 
int charCount = 0;     

/* Function: Scrolling Texts */
// The function acepts 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 Intergration */
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 Display  
  // convert MQ-2's value to ASCII code
  int ascii_value = map(mq2g3V, 1000, 2500, 34, 126);
  char ascii_char = (char)ascii_value;

  // a new character is added to the string (the previous one is kept)
  dialogue += ascii_char ;
  charCount++; // a ccumulated 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 display 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

// LCD Display
  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);
}

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