Beste CebeciSwarna ManjariHeba Elidrisi
Published

Echoes of Earth

Echoes of Earth is a soil sensing device that reads ground data and visualises it through light and sound outputs.

IntermediateWork in progress74

Things used in this project

Hardware components

Gravity: Analog Soil Moisture Sensor For Arduino
DFRobot Gravity: Analog Soil Moisture Sensor For Arduino
×1
LED (generic)
LED (generic)
×3
Barduino
×2

Software apps and online services

Rhinoceros 3D
Arduino IDE
Arduino IDE
Touchdesigner

Hand tools and fabrication machines

Laser cutter (generic)
Laser cutter (generic)

Story

Read more

Custom parts and enclosures

4ecdb6f6-1955-4329-a957-803e3138171f_IPhKKAA3T7.gif

prototype

screenrecord_12nCG1ioWv.mp4

whatsapp_image_2026-02-06_at_12_47_25_WIMTp2ZjNb.jpeg

whatsapp_image_2026-02-06_at_14_08_57_i43FSp4lKo.jpeg

img_3769_uaa8wDRFhW.jpg

img_3800_ubwcBlumOd.jpg

everything works together!

We tried connecting the sensor to the visual and sound outputs on touchdesigner.

Schematics

circuit diagram

prototype electronics placement

Code

sender code

Arduino
#include <esp_now.h>
#include <WiFi.h>


// ------------------- PINS -------------------
const int leds[3] = {9, 10, 11}; // LED pins
const int soilPin = 18;          // Analog pin for soil sensor


// ------------------- LED FLICKER -------------------
bool ledState[3] = {0};
unsigned long lastLEDTime[3] = {0};
unsigned long ledInterval[3] = {100, 150, 200};


// ------------------- SOIL SENSOR -------------------
unsigned long lastSoilTime = 0;
unsigned long soilInterval = 1000; // send every second


// ------------------- ESP-NOW -------------------
uint8_t broadcastAddress[] = {0x10, 0x20, 0xBA, 0x14, 0x30, 0xF8};


typedef struct struct_message {
 int soilValue;
} struct_message;


struct_message myData;
esp_now_peer_info_t peerInfo;


// Callback when data is sent
void OnDataSent(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
 Serial.print("Send Status: ");
 Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}


// ------------------- SETUP -------------------
void setup() {
 Serial.begin(115200);


 // LED pins
 for (int i = 0; i < 3; i++) pinMode(leds[i], OUTPUT);
 pinMode(soilPin, INPUT);


 // Wi-Fi in Station mode
 WiFi.mode(WIFI_STA);


 // Init ESP-NOW
 if (esp_now_init() != ESP_OK) {
   Serial.println("Error initializing ESP-NOW");
   return;
 }


 // Register send callback
 esp_now_register_send_cb(OnDataSent);


 // Register peer
 memcpy(peerInfo.peer_addr, broadcastAddress, 6);
 peerInfo.channel = 0;
 peerInfo.encrypt = false;
 if (esp_now_add_peer(&peerInfo) != ESP_OK) {
   Serial.println("Failed to add peer");
   return;
 }


 Serial.println("Sender ready");
}


// ------------------- LOOP -------------------
void loop() {
 unsigned long now = millis();


 // -------- LED FLICKER --------
 for (int i = 0; i < 3; i++) {
   if (now - lastLEDTime[i] >= ledInterval[i]) {
     ledState[i] = !ledState[i];
     digitalWrite(leds[i], ledState[i]);
     lastLEDTime[i] = now;
     ledInterval[i] = random(50, 500); // random flicker interval
   }
 }


 // -------- SOIL SENSOR & ESP-NOW --------
 if (now - lastSoilTime >= soilInterval) {
   int soilValue = analogRead(soilPin);
   myData.soilValue = soilValue;


   Serial.print("Soil value: ");
   Serial.println(soilValue);


   esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&myData, sizeof(myData));
   if (result != ESP_OK) Serial.println("Error sending data");


   lastSoilTime = now;
 }
}

Receiver Code

Arduino
#include <esp_now.h>
#include <WiFi.h>


// Data structure (must match sender!)
typedef struct struct_message {
 int soilValue;
} struct_message;


struct_message incomingData;


// Callback function when data is received
void OnDataRecv(const esp_now_recv_info_t *recv_info, const uint8_t *incomingDataPtr, int len) {
 memcpy(&incomingData, incomingDataPtr, sizeof(incomingData));
  Serial.println(incomingData.soilValue);
 delay(100);
}


void setup() {
 Serial.begin(115200);


 // Set device as a Wi-Fi Station
 WiFi.mode(WIFI_STA);


 // Init ESP-NOW
 if (esp_now_init() != ESP_OK) {
   Serial.println("Error initializing ESP-NOW");
   return;
 }


 // Register receive callback
 esp_now_register_recv_cb(OnDataRecv);


 Serial.println("Receiver ready, waiting for soil data...");
}


void loop() {
 // Nothing needed here; data handling happens in callback
}

LED flicker code

Arduino
const int soilPin = 18;
const int leds[5] = {7,8,9,10,11};

void setup() {
  Serial.begin(115200);
  analogSetAttenuation(ADC_11db);
  

  for (int i = 0; i < 5; i++) {
    pinMode(leds[i], OUTPUT);
  }
}

void loop() {
  int soil = analogRead(soilPin);
  Serial.println(soil);

  if (soil == 0) soil = 2000;  // fallback

  for (int i = 0; i < 5; i++) {
    int minD = map(soil, 0, 4095, 20 + i * 10, 150 + i * 20);
    int maxD = map(soil, 0, 4095, 100 + i * 40, 400 + i * 60);
    flicker(leds[i], minD, maxD);
  }
}

void flicker(int pin, int minDelay, int maxDelay) {
  digitalWrite(pin, HIGH);
  delay(random(minDelay, maxDelay));
  digitalWrite(pin, LOW);
  delay(random(minDelay, maxDelay));
}

Credits

Beste Cebeci
1 project • 0 followers
Swarna Manjari
1 project • 0 followers
Heba Elidrisi
1 project • 0 followers

Comments