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 provided1,673
Soil Moisture Meter that Chirp

Things used in this project

Hardware components

SparkFun ESP8266 Thing - Dev Board
SparkFun ESP8266 Thing - Dev Board
SparkFun Soil Moisture Sensor (with Screw Terminals)
SparkFun Soil Moisture Sensor (with Screw Terminals)
SparkFun MicroView - OLED Arduino Module
SparkFun MicroView - OLED Arduino Module

Software apps and online services

Arduino IDE
Arduino IDE
myDevices Cayenne


Read more


Soil Moisture Meter Breadboard

Soil moisture meter bb z57dbdi6lo



// 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

42 projects • 123 followers
mok mun fong

mok mun fong

1 project • 0 followers


Add projectSign up / Login