Line 11: | Line 11: | ||
== Project Concept == | == Project Concept == | ||
The Air Between Us is a new media exploration through a cybernetic approach, integrating electronic sensors with biological systems. By creating two isolated plant systems and analyzing their environmental data, the work attempts to simulate and observe potential interaction and "communication" between the living organisms through the shared mechanism. | The Air Between Us is a new media exploration through a cybernetic approach, integrating electronic sensors with biological systems. By creating two isolated plant systems and analyzing their environmental data, the work attempts to simulate and observe potential interaction and "communication" between the living organisms through the shared mechanism. | ||
A Helleborus in a sealed autoclave bag containing MS Media and several Sundew plants in a glass jar with the same cultivation medium serve as the two independent systems. Due to the constraints of placing sensors directly inside the sealed environments, I decided to create a shared mechanism that using custom-made transparent plastic boxes. Inside each box, an MQ-2 gas sensor and a DHT22 temperature and humidity sensor were installed to measure emitted gases and environmental conditions, which were channeled through plastic tubes extended from the sealed plants environment. A third sensor box acts as a bridge between the two plant systems, capturing any atmospheric interactions that may arise when they are connected. | |||
=== Brainstorming === | === Brainstorming === |
Revision as of 16:49, 21 February 2025
Project : The Air Between Us
This project integrates technology and nature, attempting to explore the invisible communication of plants. The use of sensors and IoT to uncover the hidden exchanges of gases and environmental data between isolated plant systems. By connecting their ecosystems through shared mechanisms, it transforms plant interactions into visible and tangible sensory experiences.
Initial Idea
-
Project Concept
The Air Between Us is a new media exploration through a cybernetic approach, integrating electronic sensors with biological systems. By creating two isolated plant systems and analyzing their environmental data, the work attempts to simulate and observe potential interaction and "communication" between the living organisms through the shared mechanism.
A Helleborus in a sealed autoclave bag containing MS Media and several Sundew plants in a glass jar with the same cultivation medium serve as the two independent systems. Due to the constraints of placing sensors directly inside the sealed environments, I decided to create a shared mechanism that using custom-made transparent plastic boxes. Inside each box, an MQ-2 gas sensor and a DHT22 temperature and humidity sensor were installed to measure emitted gases and environmental conditions, which were channeled through plastic tubes extended from the sealed plants environment. A third sensor box acts as a bridge between the two plant systems, capturing any atmospheric interactions that may arise when they are connected.
Brainstorming
Sketches
Moodboard
Preparation ( 2 Isolated Plant Systems)
MS Media
-
Recipe:
1 Liter Water: | |
---|---|
Murashige | 4.5 g |
Gelrite | 5 g |
D(+) Saccharose
(sugar) |
20 g |
Sterilizing & Transplanting
-
Plants Observation
Documented Period : 02.11.2024 - 08.02.2025
Prototype
Electronics / Circuits
Circuits Diagram Software: Cirkit Designer
Programming
Code:
platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
arduino-libraries/ArduinoHttpClient@^0.6.1
mathworks/ThingSpeak@^2.0.0
adafruit/DHT sensor library@^1.4.6
marcoschwartz/LiquidCrystal_I2C@^1.1.4
main.cpp
/*
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 real-time uploaded )
Winterwerkschau Exhibition
-
Technical Riders
General Set Up | Installation Materials | Technical Equipment | |||
---|---|---|---|---|---|
Space | ~ 200 x 150 x 200cm | ESP32 | Mac mini | ||
Table | 120 x 80cm | DHT22 Sensors | *3 | Monitor | vertical |
Stand with hooks
( Infusionsständer ) |
10k Ω Resistors | *3 | Extension Cord | ~ 3 - 4 sockets | |
Notice:
The power and WiFi must remain on for the sensor data to be continuously uploaded and synchronized 24/7 via WiFi to the ThingSpeak (IoT platform). |
MQ-2 Sensors | *3 | HDMI cable | ||
LCD 16x2 | LED Lamp | ||||
Breadboard | 5V External Power Supply | ||||
Jump Wires | a lot | ESP32 Type C Cable + Adapter | |||
Autoclave Bags | *3 | ||||
Glass Jar + Cap
(Rundglas + Trinkhalmdeckel) |
|||||
Transparent Plastic Boxes
(Klarsichtfaltschachtel) |
*3 | ||||
Transparent Plastic Bags
(Klarsichttüten klein) |
*3 | ||||
Cottons | |||||
Tubes | |||||
Ms Media | |||||
Plants | Helleborus, Sundew |
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