Bob
Published © GPL3+

Soil Moisture Probe for Home or Garden

Self-contained, battery operated probe that sends email alerts, using IFTTT, when soil moisture or battery are low.

IntermediateFull instructions provided4 hours1,495
Soil Moisture Probe for Home or Garden

Things used in this project

Hardware components

Hammond Project Box, (1551KBK)
×1
Adafruit LIPO Battery 1200 mAh
×1
Sparkfun Thing WRL-13231
×1
SparkFun Soil Moisture Probe, SEN-13322
×1
Fairchild N-Channel MOSFET (BS270)
Sold by Digi-key
×2
Resistor 10k ohm
Resistor 10k ohm
×1
Resistor 4.75k ohm
Resistor 4.75k ohm
×1
Resistor 2.21k ohm
Resistor 2.21k ohm
×1
Adafruit Bakelite Perf Board (PID:2670)
×1
SparkFun 22 AWG Hook-up Wire (PRT-08022)
Multiple Colors (Red, White, Black, Yellow)
×1
SparkFun Break Away Header Male Pins (PRT-12693)
×6
SparkFun Break Away Male Headers - Right Angle
×3
Pololu Female Crimp Pins (pn 1930)
×3
Pololu Female Crimp Housing (pn 1900)
×3

Software apps and online services

Arduino IDE
Arduino IDE
Arduino-ifttt-maker-master
Arduinojson-master

Hand tools and fabrication machines

Wire cutters
Wire strippers
Soldering iron (generic)
Soldering iron (generic)
Dremel
with cutoff wheel and 1/8 routing bit
Files (large and small)
Combination square
Needle nose pliers

Story

Read more

Schematics

Soil Moisture Schematic

Overview of Sparkfun Thing, Soil Moisture sensor, and Voltage Dividers

Code

Soild Moisture IFTTT

Arduino
Use this code with Arduino IDE. Download code to soil moisture probe.
/*****************************************************************************
* Program Name: soilMoisture
* Author: Bob
* 
* This program is used in conjunction with the build out instructions for a
* soil moisture probe that can measure both soil moisture and battery voltage.
* Both measurements are analog and both require different voltage dividers.
* That requires some additional circuitery to be built so the Thing's ADC can
* measure both. See the build out instructions for more information.
* 
* This program will measure soil moisture and battery voltage, and send you
* an email via IFTTT when either are low. This program will also send 
* status messages so you know it is working.
* 
* Additionally, this program has two test modes (besides operational mode),
* uses deep sleep to conserve battery usage, uses EEPROM memory to save data 
* during a deep sleep, and can determine the best WIFI to use if you have 
* multiple WIFI in your house. You can also have multiple sensors because each 
* sensor can have its own name and the name will be in the IFTTT email.
* 
* The deepSleep can only sleep 71 minutes. To sleep longer then that multiple 
* sleeps are needed.
* 
* The WAKE_RF_DISABLED has the lowest power draw, but there seems to be a bug 
* where WIFI does not work after sleeping with WAKE_RF_DISABLED. The workaround 
* is to do another deep sleep with WAKE_RF_DEFAULT.
* 
* You will need to setup an IFTTT account and an IFTTT Maker applet before you
* set the program to operational mode. Its easy.
* 
* Also, you can ground pin 5, at power on time, and force a status message.
* This comes in handy when their are long time spans between status messages 
* and you want to ensure the sensor is working. Power off the sensor, ground
* pin-5, power on the sensor, remove the ground after a few seconds, and you 
* should get an email within a minute or so.
* 
* 
* Functions         Description
* ----------------- ------------------------------------------------------------
* xdelay()          Breakup long delays into short delays so background wifi runs
* findWIFI()        Find best wifi when you have wifi extenders in your house
* connectWIFI()     Connect to the wifi
* sigQuality()      Convert RSSI db into english
* sendStatus()      Send a status message to IFTTT
* sendAlert()       Send an alert message to IFTTT
* readMoistSensor() Read moisture sensor and check if low moisture
* readBattVoltage() Read batter sensor and check if low voltage
* mainProcess()     Check if time to measure or send an IFTTT message
* rwEEPROM()        Read write important data to EEPROM
* setup()           Called first on power up or awake from deep sleep
* loop()            Called after setup(). Controls deep sleep
* ------------------------------------------------------------------------------
* 
* Change History
* Date         Name   Ver    Description
* ----------   ----   ----   ---------------------------------------------------
* 11/01/2016    BOB   V1.0   Initial delivery
* 03/12/2018    BOB   V1.1b  Changed default sleep from 1usec to 1msec.
*                            1usec sleep hangs. probably due to software update.
*                              Corrected myNetwork indexing. It was reversed
*                            Add xdelay function to help wifi background tasks.
*                              Use xdelay for delays > 10msec
*                            Simplified moisture measurment
*                            Simplified battery measurment
* 03/12/2018    BOB   V1.1c  Reorganized EEPROM data
*                            Fixed bug in connectWIFI
*                            Added wifi rescan on wifi connect failure
*                            Moved main process in loop() to its own function.
* 03/13/2018    BOB   V1.2   Ready for production
* 03/14/2018    BOB   V1.3   Made changes to myNetwork tabe
*                            Made changes to IFTTT status message
* 03/15/2018    BOB   V1.4   Problems with EEPROM in test mode 2,
*                            added delays, moved EEPROM.end, killed wifi radio
*                            Fixed sleep issue with test mode 1.
*                            Added pin-5 force status message
* 03/16/2018    BOB   V1.5   Swapped test 1 and 2 around. Makes better sense
*                            with the instructions
* 
*****************************************************************************/
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <EEPROM.h>
#include <IFTTTMaker.h>

/***********************************************************/
/* Define test/operational mode and debug print statements */
#define TESTMODE 1  // 0 = operational mode, 
                    // 1 = test mode, no WIFI, no IFTTT and 5 second sleeps 
                    // 2 = test mode, uses WIFI,IFTTT,Status messages only, and 60 second deep sleeps
                    
#define DEBUG    1  // 0 = no print info, 
                    // 1 = print info (use with IDE serial monitor)
#define VERSION  "v1.5"
                    
/************************************************************************/
/* Define your WIFI networks. End strings in zero for string processing */
/* Choose 1 or multiple WIFI's using comments below                     */
//#define MAX_NETWORKS  3
//const char *myNetwork[][2] = 
//{ {"mywifi\0"     ,"wifipassword1\0"},
//  {"mywifi_ext\0" ,"wifipassword2\0"},
//  {"mywifi_ex2\0" ,"wifipassword3\0"} 
//};
#define MAX_NETWORKS  1
const char *myNetwork[][2] =  {"mywifi\0"    ,"mywifipassword1\0"};

/**********************************************************/
/* Define IFTTT event name and KEY                        */
#define EVENT_NAME "SoilMoisture"       // Name of your event name, set when you are creating the applet
#define KEY "put-key-from-ifttt-here"   // Get it from this page https://ifttt.com/services/maker/settings
#define SENSOR_NAME "Test"              // Sensors unique name. Used in the IFTTT email

/************************************************************************/
/* Define alert criteria. Send message to IFTTT if below the alert value*/
#define LOWMOISTURE 60                 // Percent moisture value needed to trigger a "low moisture" email
#define LOWCHARGE   20                 // Percent battery charge value needed to trigger a "low battery" email



/**********************************************************/
/* Define pins for sensors */
#define BATTPIN  13  //Digital IO pin to turn on sensor 1 MOSFET
#define MOISTPIN 12  //Digital IO pin to turn on sensor 2 MOSFET
#define MPOWER    4  //Digital IO pin to power the soil moisture probe

/**********************************************************/
/* Define max values (for calibration)                    */
#define MAXMOISTURE 1.068  //max output  voltage of moisture voltage divider(R1=4.60K, R2=2.2K, Vin=3.3v)
#define MAXBATVOLTS 5.409  //max battery voltage of battery  voltage divider(R1=9.97K, R2=2.2K, Vout=1.0v)
#define MAXBATTERY  4.2    //max battery voltage of the battery
#define MINBATTERY  3.2    //min battery voltage to run Sparkfun Thing.

/**********************************************************/
/* Deep sleep controls                                    */
#define USECS 3600000000       // usecs to sleep (1 hour)
#define MOISTCOUNT          4  // Define number of sleeps before taking a moisture measurment (every 4 hours)
#define BATTCOUNT          24  // Define number of sleeps before taking a battery measurment (1 day)
#define STATUSCOUNT       168  // Define number of sleeps before sending a status trigger to IFTTT (1 week)

/**********************************************************/
/* set up wifi and IFTTT client                           */
WiFiClientSecure  client;
IFTTTMaker        ifttt(KEY, client);

/**********************************************************/
/* Items saved in eeprom during deep sleep                */
/* Use 'union' for easy read/write of EEPROM              */
typedef struct {
  int           sendMsg;         // Flag. 0=no IFTTT messages to send, 1=send low moisture, 2=send low voltage, 4=send status message
  unsigned long sleepCount;      // The number of deep sleeps since the last status message
  float         moisture;        // last moisture reading
  float         battery;         // last battery voltage reading
  int           charge;          // last battery reading in percent charged
  int           rssi;            // last rssi reading
  int           netIndex;        // index into myNetwork table of wifi last used.
}ESTRUCT;

union {
  ESTRUCT data;                  // Reference data with "u.data.xxx"
  byte    b[sizeof(ESTRUCT)];    // Reference data with "u.b[ ]"
}u;





/********************************************************************
 *  xdelay()
 *  Helps wifi background tasks run during long wait times.
 *  myDelay = msec. 
 ********************************************************************/
void xdelay(int myDelay)
{
  for(int i=0; i<myDelay; i+=10) { 
    delay(10);
    yield();
  }
}



/********************************************************************
 *  findWIFI()
 *  Scans all networks looking for networks listed in the 
 *  myNetworks table. Returns the table index of the network with
 *  the strongest RSSI
 * 
 *  If none of your networks are found, we loop. forever!!!
 ********************************************************************/
int findWIFI()
{
  int bestIndex = -1; 
  int bestRSSI  = -1000;
  
  if(DEBUG) { Serial.println("findWIFI");}

  // Set WiFi to station mode and disconnect from an AP if it was previously connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  xdelay(100);

  //Loop till we find a network we can use
  while(1) {

    // WiFi.scanNetworks will return the number of networks found
    int n = WiFi.scanNetworks();
    if (n > 0) {

      //Loop through ALL WIFI networks found.
      for (int i = 0; i < n; ++i) {
        if(DEBUG) { Serial.print("  "); Serial.print(WiFi.SSID(i)); Serial.print(" "); Serial.println(WiFi.RSSI(i));}

        //Loop through OUR networks for a match. Save best RSSi and index
        for(int j = 0; j < MAX_NETWORKS; j++) {
          if(WiFi.SSID(i) != myNetwork[j][0]) continue;
          if(WiFi.RSSI(i) > bestRSSI) {
            bestRSSI = WiFi.RSSI(i);
            bestIndex = j;
          }
        }
      }
    }

    //If network found, break loop, otherwise slep a few seconds then try again
    if(bestIndex != -1) break;
    if(DEBUG) { Serial.println("!!! No WIFI Found");}
    xdelay(5000);
  }
  u.data.rssi = bestRSSI; //save rssi for status
  return bestIndex;
}



/*******************************************
 *  connectWIFI()
 *  Find best network and connect to it.
 *  If connection fails, retry.
 *  Don't use wifi in testmode 1             
 *******************************************/
void connectWIFI()
{
  //no wifi in testmode 2
  if(TESTMODE == 1) return;

  if(DEBUG) { Serial.println("connectWIFI");}

  //loop till we are connected
  while(1) {
    
    // Find the best WIFI to use. dont come back here till we have a usable network
    // Skip this step if only one network (saves battery)
    if(( u.data.netIndex < 0) || (u.data.netIndex > MAX_NETWORKS-1)){
      u.data.netIndex = findWIFI();
    
    //  if(MAX_NETWORKS > 1) u.data.netIndex = findWIFI();
    //  else                 u.data.netIndex = 0;
    }
  
    // Start WiFi connection
    if(DEBUG) { Serial.print("  Using WIFI "); Serial.println(myNetwork[u.data.netIndex][0]);}
    if(DEBUG) { Serial.print("  connecting .");}
    WiFi.begin(myNetwork[u.data.netIndex][0], myNetwork[u.data.netIndex][1]);

    // Try to connect within 30 seconds
    for(int i=1;i<=30;i++) {
      if(WiFi.status() == WL_CONNECTED) break;
      xdelay(1000);
      if(DEBUG) { Serial.print(".");}
     }
    Serial.println("");

    //If we did not connect re-scan and try again
    if(WiFi.status() != WL_CONNECTED) {
      if(DEBUG) { Serial.println("  !!! Failed to connect");}
      u.data.netIndex = -1;
      continue;
    }
 
    // we are connected. print status
    if(DEBUG) { Serial.println("  WiFi connected");}
    if(DEBUG) { Serial.print("  IP address: "); Serial.println(WiFi.localIP());}
    if(DEBUG) { Serial.print("  RSSI     ");    Serial.println(u.data.rssi); }
    return;
  }
  
}



/********************************************
 *  sigQuality()
 *  Convert RSSI into signal quality
 *  Excellect = > -50
 *  Good      = < -50 && > -60
 *  Fair      = < -60 && > -70
 *  Week      = < -70
 ********************************************/
String sigQuality(int rssi)
{
  if(DEBUG) { Serial.println("  sigQuality"); }
  String quality = "";

  if(rssi >= -50) {
    quality = "Excellent";
  }
  else if((rssi < -50) && (rssi >= -60)) {
    quality = "Good";
  }
  else if((rssi < -60) && (rssi >= -70)) {
    quality = "Fair";
  }
  else {
    quality = "Week";
  }

  return quality;
}



/********************************************
 *  sendStatus()
 *  Send a status message to IFTTT. The message has
 *  current moisture and voltage readings.
 *  IFTTT will send us an email.
 *  Note: <br /> is used to make a multi-line message.
 *  This may not work on all emails.
 ********************************************/
void sendStatus()
{
  if(TESTMODE==1) return; //only testmode 0 or 2 allowed to continue down
  if(DEBUG) { Serial.println("sendStatus"); }

  //connect to wifi if necessary
  if(WiFi.status() != WL_CONNECTED) connectWIFI();

  String moistStat = "Okay";
  if(u.data.moisture <= LOWMOISTURE) moistStat ="LOW";
  
  String battStat  = "Okay";
  if(u.data.charge <= LOWCHARGE) moistStat ="LOW";
  
  String wifiStat = sigQuality(u.data.rssi);
  
  //compose the status message. message has html line breaks for readability
  String data = "";
  data.concat("<br />SENSOR STATUS<br />");
  
  data.concat("<br />Moisture is "); data.concat(moistStat);
  data.concat("  ("); data.concat(int(u.data.moisture)); data.concat("%)");
  
  data.concat("<br />Battery is "); data.concat(battStat);
  data.concat("  (");data.concat(int(u.data.charge));data.concat("%)");
  
  data.concat("<br />WIFI is "); data.concat(wifiStat);
  data.concat("  ("); data.concat(u.data.rssi); data.concat("db)");
  
  data.concat("<br />Software version  is "); data.concat(VERSION);
     
  // try 5 times to send IFTTT message, break out of loop on "good" send
  for(int a = 0; a < 5; a++) {
    if(ifttt.triggerEvent(EVENT_NAME,SENSOR_NAME,data,"")){
      if(DEBUG) { Serial.println("  Status message sent successfully"); }
      break;
    } 
    else {
      if(DEBUG) { Serial.println("  Status message Failed! Retry");}
      xdelay(5000);
    }
  }
  u.data.rssi=WiFi.RSSI(); //in single networks a good rssi comes after we send a message
}



/********************************************
 *  sendAlert()
 *  Send either a low voltage/charge or low
 *  soil-moisture alert message to IFTTT.
 *  IFTTT will send us an email.
 *  Note: <br /> is used to make a multi-line message.
 *  This may not work on all emails.
 ********************************************/
void sendAlert (int msgType)
{
  //Only send alerts in operational mode (testmode=0)
  if(TESTMODE) return; //only testmode 0 allowed to continue down
  if(DEBUG) { Serial.println("sendAlert"); }

  String data = "";
  if(msgType == 2) {  
    data.concat("<br />Battery LOW!<br />");
    data.concat("<br />Charge is ");data.concat(int(u.data.charge)); data.concat("%");
    data.concat(" (");  data.concat(u.data.battery);data.concat("v)");
  }
  else if(msgType == 1) {
    data.concat("<br />Soil Moisture LOW!<br />");
    data.concat("<br />Moisture = "); data.concat(int(u.data.moisture)); data.concat("%");
  }
  else {
    return; //unknown alert type
  }
  
  //connect to wifi if necessary
  if(WiFi.status() != WL_CONNECTED) connectWIFI();
  
  // try 5 times to send message, break out of loop on "good" send
  for(int a = 0; a < 5; a++) {
    if(ifttt.triggerEvent(EVENT_NAME,SENSOR_NAME,data,"")){
      if(DEBUG) { Serial.println("  Alert sent successfully"); }
      break;
    } 
    else {
      if(DEBUG) { Serial.println("  Alert Failed! Retry"); }
      xdelay(5000);
    }
  }
  u.data.rssi=WiFi.RSSI(); //in single networks a good rssi comes after we send a message
}



/******************************************************** 
 *  readMoistSensor()
 *  Turn on power and mosfet gate, read sensor, and convert
 *  to a %percentage.
 *  Send IFTTT a trigger if low moisture
 ********************************************************/
int readMoistSensor()
{
  if(DEBUG) { Serial.println("readMoistSensor");}

  //Turn on powerand mosfet gate, measure, turn off power and gate
  digitalWrite(MPOWER, HIGH);
  digitalWrite(MOISTPIN, HIGH);
  delay(1);
  int sensorValue = analogRead(A0);
  digitalWrite(MPOWER, LOW);
  digitalWrite(MOISTPIN, LOW);

  //Convert A0 to ADC voltage, then a percent of MAXMOISTURE volts (max voltage)
  float moistureVolts  = (sensorValue > 0 ? sensorValue * (MAXMOISTURE/1024.0) : .001);
  u.data.moisture = (moistureVolts<MAXMOISTURE ? 100-((MAXMOISTURE-moistureVolts)*(100/MAXMOISTURE)) : 100);
    
  if(DEBUG) { Serial.print("  Moisture A0    "); Serial.println(sensorValue); }
  if(DEBUG) { Serial.print("  Moisture Volts "); Serial.println(moistureVolts); }
  if(DEBUG) { Serial.print("  Moisture MAX   "); Serial.println(MAXMOISTURE); }
  if(DEBUG) { Serial.print("  Moisture       "); Serial.println(u.data.moisture); }

  //If moisture low, return 'alert' status
  if(u.data.moisture <= LOWMOISTURE) {
    if(DEBUG) { Serial.println("  Moisture LOW");}
    return 1;
  }
  if(DEBUG) { Serial.println("  Moisture OK");}
  return 0;
}



/******************************************************** 
 *  readBattVoltage()
 *  Turn on mosfet gate, read voltage, and convert
 *  to a %percentage of "operational" voltage.
 *  Send IFTTT a trigger if low voltage
 ********************************************************/
int readBattVoltage()
{
  if(DEBUG) { Serial.println("readBattVoltage");}

  //Turn on mosfet gate, measure battery, turn off gate
  digitalWrite(BATTPIN, HIGH);
  delay(1);
  int sensorValue = analogRead(A0);
  digitalWrite(BATTPIN, LOW);

  /*Calculate battery voltage and charge (0% = (3.2v) and 100% >= 4.2v)*/
  u.data.battery = sensorValue * (MAXBATVOLTS/1024.0);
  u.data.charge = (u.data.battery < MAXBATTERY ? 100-( (MAXBATTERY-u.data.battery) * (100/(MAXBATTERY-MINBATTERY)) ) : 100);

  if(DEBUG) { Serial.print("  Battery A0     "); Serial.println(sensorValue); }
  if(DEBUG) { Serial.print("  Battery Volts  "); Serial.println(u.data.battery); }
  if(DEBUG) { Serial.print("  Battery MAX    "); Serial.println(MAXBATTERY); }
  if(DEBUG) { Serial.print("  Battery charge "); Serial.println(u.data.charge); }

  //If charge is low, return 'alert' status
  if(u.data.charge <= LOWCHARGE) {
    if(DEBUG) { Serial.println("  Charge LOW");}
    return 2;
  }
  if(DEBUG) { Serial.println("  Charge OK");}
  return 0;
}



/******************************************************** 
 *  mainProcess()
 *  See if time to measure or send a message
 *  sendMsg, 0=no alerts, 1=moisture low, 2=battery low, 4=send status
 ********************************************************/
void mainProcess()
{
  if(DEBUG) { Serial.println("mainProcess");}
  // send alert or status if necessary
  // you could send all 3 
  if((u.data.sendMsg >= 1) && (u.data.sendMsg <= 7)){  
    if((u.data.sendMsg & 0x01) != 0) sendAlert(1);
    if((u.data.sendMsg & 0x02) != 0) sendAlert(2);
    if((u.data.sendMsg & 0x04) != 0) sendStatus();
    u.data.sendMsg=0; //reset to "no alerts" after sending alerts/status
  }

  // If we did not send a message, see if we need to get measurements
  else {

    //If we are going to send status or EEPROM has been initialized, 
    //get all measurments and send status.
    //always send a status message in test mode 1
    if((u.data.sleepCount % STATUSCOUNT == 0) || (TESTMODE == 1)){
      if(DEBUG) { Serial.println("  Updating Status"); }
      readBattVoltage();
      readMoistSensor();
      u.data.sendMsg=4;
    }

    // otherwise see if time to get moisture or battery measurements
    else {
      if(u.data.sleepCount % BATTCOUNT == 0)   u.data.sendMsg += readBattVoltage();
      if(u.data.sleepCount % MOISTCOUNT == 0)  u.data.sendMsg += readMoistSensor();
    }
  } 
}



/******************************************************** 
 *  rwEEPROM()
 *  Read or write the u.data structure to EEPROM.
 *  Use the byte portion of the union to do block read/write.
 * 
 *  wFlag 0=read, 1=write
 ********************************************************/
void rwEEPROM(int wFlag) {
  if(DEBUG) { Serial.println("rwEEPROM"); }

  /* Startup EEPROM */
  EEPROM.begin(sizeof(ESTRUCT));
  delay(1); //let background tasks run
  /* read EEPROM */
  if(wFlag == 0) {
    if(DEBUG) { Serial.println("  Read  eeprom"); }
    for(unsigned int x=0;x<sizeof(ESTRUCT);x++) { u.b[x]  = EEPROM.read(x);}
  }
  /* write EEPROM */
  else {
    if(DEBUG) { Serial.println("  Write eeprom"); }
    for(unsigned int x=0;x<sizeof(ESTRUCT);x++) { EEPROM.write(x,u.b[x]); }
    delay(1);//let background tasks run
  }
  /* stop EEPROM */
  EEPROM.end();  //use end or commit to actually save data in eeprom
  delay(1);//let background tasks run
}



/******************************************************** 
 *  setup
 *  The setup routine. Run once at startup.
 *  We start here after every sleep.
 ********************************************************/
void setup() 
{
   /* init print */
   if(DEBUG) { Serial.begin(115200); }
   if(DEBUG) { Serial.print("\nsetup, test mode="); Serial.println(TESTMODE); }

   /* Force a status message if pin 5 is grounded at power on */
   /* You have 5 senonds to remove the ground after powering on */
   pinMode(5, INPUT_PULLUP);
   if(!digitalRead(5)) {
      xdelay(5000);
      pinMode(5, OUTPUT);
      digitalWrite(5,LOW);
      rwEEPROM(0);
      u.data.sleepCount = STATUSCOUNT;
      rwEEPROM(1);
   }
   pinMode(5, OUTPUT);
   digitalWrite(5,LOW);

   /* Init pins */
   pinMode     (BATTPIN,   OUTPUT);
   digitalWrite(BATTPIN,   LOW);

   pinMode     (MOISTPIN,  OUTPUT);
   digitalWrite(MOISTPIN,  LOW);

   pinMode     (MPOWER,    OUTPUT);
   digitalWrite(MPOWER,    LOW);

}



/******************************************************** 
 *  loop
 *  The main loop.
 ********************************************************/
void loop() 
{
  if(DEBUG) { Serial.println("loop"); }

  // read, saved varaibles from eeprom
  rwEEPROM(0);
  Serial.print("  read sleepCount = "); Serial.println(u.data.sleepCount);
  Serial.print("  read sendMsg    = "); Serial.println(u.data.sendMsg);

  //check for initialized EEPROM (all eeprom is -1)
  if(u.data.sendMsg == -1) {
    if(DEBUG) { Serial.println("Initialize EEPROM"); }
    u.data.sendMsg = 0;
    u.data.sleepCount = STATUSCOUNT;
  }

  // see if time to measure or send message
  mainProcess();

  // Update sleep count if necessary, and save data in EEPROM 
  // dont update sleepCount if we are going to send a message
  if(u.data.sendMsg==0) u.data.sleepCount++;
  if(TESTMODE == 1) u.data.sendMsg=0; //reset sendMsg in test mode 1. we only want to measure
  if(TESTMODE == 2) u.data.sleepCount=STATUSCOUNT; //Keep sending status messages in test mode 2
  rwEEPROM(1);
  Serial.print("  write sleepCount = "); Serial.println(u.data.sleepCount);
  Serial.print("  write sendMsg    = "); Serial.println(u.data.sendMsg);

  // Go to sleep. Use "delay" in testmode 1
  if(TESTMODE == 1) {
    WiFi.mode( WIFI_OFF ); //shut off radio in test mode 1
    if(DEBUG) { Serial.print("TESTMODE ");Serial.print(TESTMODE);Serial.println(", Sleeping 5 seconds");}
    xdelay(5000);         //sleep 3 seconds
  }
  else {

    // deepest sleep if no messages to send
    // only sleep 60 seconds in test mode 2.
    if(u.data.sendMsg == 0) {
      if(DEBUG) { Serial.println("Sleeping with RF_DISABLED"); xdelay(50); }
      unsigned long xsleep = (TESTMODE == 2 ? 60000000:USECS);
      ESP.deepSleep(xsleep, WAKE_RF_DISABLED); // Deep Sleep
      xdelay(3000); //delay till sleep takes affect. Upon awake, start loop() from the beginning
    }

    // reset wifi via deepsleep w/RF_DEFAULT if message to be sent. sleep 1 usec
    else {
      if(DEBUG) { Serial.println("Sleeping with RF_DEFAULT"); xdelay(50); }
      ESP.deepSleep(1000, WAKE_RF_DEFAULT); // Deep Sleep
      xdelay(10000); //delay till sleep takes affect. Upon awake, start loop() from the beginning
    }
  }
}

Credits

Bob

Bob

4 projects • 1 follower
Hobbiest

Comments