vincent wongmok mun fong
Published © GPL3+

Soil Moisture Meter that Chirp

Using ESP8266, soil moisture sensor, buzzer and LCD to build a soil moisture meter that chirps. Data to be displayed on Cayenne dashboard.

IntermediateFull instructions provided2,901
Soil Moisture Meter that Chirp

Things used in this project


Read more


Soil Moisture Meter Breadboard



// This example shows how to connect to Cayenne using an ESP8266 and send/receive sample data.
// Make sure you install the ESP8266 Board Package via the Arduino IDE Board Manager and select the correct ESP8266 board before compiling. 

#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>

// WiFi network info.
char ssid[] = "ssid";
char wifiPassword[] = "wifiPassword";

// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "MQTT_USERNAME";
char password[] = "MQTT_PASSWORD";
char clientID[] = "CLIENT_ID";

unsigned long lastMillis = 0;

#include <SPI.h>  // Include SPI if you're using SPI
#include <SFE_MicroOLED.h>  // Include the SFE_MicroOLED library

// MicroOLED Definition //
#define PIN_RESET 5    // Connect RST to pin 5
#define PIN_DC    4    // Connect DC to pin 4
#define PIN_CS    15   // Connect CS to pin 15

MicroOLED oled(PIN_RESET, PIN_DC, PIN_CS); // SPI declaration

// moisture sensor definition//
int val = 0; //value for storing moisture value 
int soilPin = A0;//Declare a variable for the soil moisture sensor 
int soilPower = 0;//Variable for Soil moisture Power

//Rather than powering the sensor through the 3.3V or 5V pins, 
//we'll use a digital pin to power the sensor. This will 
//prevent corrosion of the sensor as it sits in the soil. 

// buzzer definition //
const int buzzerPin = 16;

// We'll set up an array with the notes we want to play
// change these values to make different songs!

// Length must equal the total number of notes and spaces 

const int songLength = 18;

// Notes is an array of text characters corresponding to the notes
// in your song. A space represents a rest (no tone)

char notes[] = "cdfda ag cdfdg gf "; // a space represents a rest

// Beats is an array of values for each note and rest.
// A "1" represents a quarter-note, 2 a half-note, etc.
// Don't forget that the rests (spaces) need a length as well.

int beats[] = {1,1,1,1,1,1,4,4,2,1,1,1,1,1,1,4,4,2};

// The tempo is how fast to play the song.
// To make the song play faster, decrease this value.

int tempo = 113;

void setup() {
  //Serial.begin(9600);   // open serial over USB

  Cayenne.begin(username, password, clientID, ssid, wifiPassword);

  oled.begin();    // Initialize the OLED
  oled.clear(ALL); // Clear the display's internal memory


  pinMode(soilPower, OUTPUT);//Set D7 as an OUTPUT
  digitalWrite(soilPower, LOW);//Set to LOW so no power is flowing through the sensor

  pinMode(buzzerPin, OUTPUT);


void loop() {

  //Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
//  if (millis() - lastMillis > 10000) {
    lastMillis = millis();
    //Write data to Cayenne here. This example just sends the current uptime in milliseconds.
    Cayenne.virtualWrite(0, val);
    //Cayenne.virtualWrite(0, lastMillis);
    //Some examples of other functions you can use to send data.
    //Cayenne.celsiusWrite(1, 22.0);
    Cayenne.luxWrite(2, random(1024));   // this is data values for testing
    //Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
//  }

  if (val < 500) playNotes();


void showSplash() {
  for (int i=0; i<512; i++)
    oled.pixel(random(oled.getLCDWidth()), random(oled.getLCDHeight()));

void showMoisture() {
  oled.clear(PAGE);            // Clear the display
  oled.setCursor(0, 8);       // Set cursor to top-left
  oled.setFontType(0);         // Smallest font
  oled.print("Moisture");      // Print "A0"
  oled.setCursor(0, 24);
  oled.setFontType(2);         // 7-segment font
  oled.print(val);  // Print a0 reading

//This is a function used to get the soil moisture content
int readSoil()

    digitalWrite(soilPower, HIGH);//turn D7 "On"
    delay(10);//wait 10 milliseconds 
    val = analogRead(soilPin);//Read the SIG value form sensor 
    digitalWrite(soilPower, LOW);//turn D7 "Off"
    return val;//send current moisture value

// this function plays notes to buzzer
void playNotes() {
  int i, duration;

  for (i = 0; i < songLength; i++) // step through the song arrays
    duration = beats[i] * tempo;  // length of note/rest in ms

    if (notes[i] == ' ')          // is this a rest? 
      delay(duration);            // then pause for a moment
    else                          // otherwise, play the note
      tone(buzzerPin, frequency(notes[i]), duration);
      delay(duration);            // wait for tone to finish
    delay(tempo/10);              // brief pause between notes

int frequency(char note) 
  // This function takes a note character (a-g), and returns the
  // corresponding frequency in Hz for the tone() function.

  int i;
  const int numNotes = 8;  // number of notes we're storing

  // The following arrays hold the note characters and their
  // corresponding frequencies. The last "C" note is uppercase
  // to separate it from the first lowercase "c". If you want to
  // add more notes, you'll need to use unique characters.

  // For the "char" (character) type, we put single characters
  // in single quotes.

  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
  int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523};

  // Now we'll search through the letters in the array, and if
  // we find it, we'll return the frequency for that note.

  for (i = 0; i < numNotes; i++)  // Step through the notes
    if (names[i] == note)         // Is this the one?
      return(frequencies[i]);     // Yes! Return the frequency
  return(0);  // We looked through everything and didn't find it,
              // but we still need to return a value, so return 0.

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
  CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s",, getValue.getId(), getValue.asString());
  //Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");


vincent wong

vincent wong

80 projects • 203 followers
mok mun fong

mok mun fong

2 projects • 2 followers