| 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
Project Concept
-
Brainstorming
Sketches
Moodboard
Preparation ( 2 Isolated Plant Systems)
MS Media
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
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
 
		

