-->
Page 1 of 1

Light Sleep with DFPlayer and PIR module

PostPosted: Mon Feb 08, 2021 3:37 pm
by DSKUP
Greetings! I'm a rookie and first time poster, looking to see if anyone can offer a little help. I'm using a Wemos D1 Mini, a DFPlayer MP3 module, and an HC-SR501 pir module to create a battery-powered motion-activated sound maker. A motion sense results in a play command being sent to the MP3 player, and the LED blinks. Pretty simple. Everything "5V" is powered from the battery, which is actually ~6v. 3.3v is only used for pull-ups.

I'm utilizing Light Sleep mode in an effort to minimize idle current draw. After a period of no motion, it goes to sleep just as expected and a subsequent motion sense brings it back to life. Everything works perfectly until coming out of sleep. Once it wakes up, a subsequent motion sense does not result in the same behavior as prior to the sleep event. Instead of flashing the LED and playing the MP3, it appears to do nothing. However, watching the serial monitor it appears to pause and then start again. The countdown timer on the serial monitor will display (for example) "...10, 9, 8, {pause at the moment I wave my hand} 3, 2, 1). It is almost as if the micro is off doing something else. Strangely, it only does this if I include the code to restart SoftwareSerial after coming out of sleep. If I comment out the SoftwareSerial restart, it behaves normally coming out of sleep- except of course that the MP3 module does not play.

Can anyone offer an ideas I can explore? I would be very grateful!! :)

PS: The light sleep code comes from this great tutorial:
https://www.mischianti.org/2019/11/21/w ... gs-part-4/

Code: Select all 

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>

extern "C" {
#include "gpio.h"
}

extern "C" {
#include "user_interface.h"
}

#define WIFI_SSID       "****"
#define WIFI_PASS       "****"

// PINS
const byte ledPin = 15;                  //D8
const byte pirPin = 5;                    //D1
const byte standbyPin = 4;            //D2
const byte rxPin = 12;                    //D6
const byte txPin = 14;                    //D5


//TIMING

const byte sleepDelay = 20;             //length of idle time (s) to wait before going to sleep
const byte standbyDelay = 30;         // initial delay (s) from power-up w/ standby button pressed
boolean justAwoke = false;
long triggerBaseline = 0;
const byte WiFiTimeout = 30;             // WiFi connect timeout (s)
const byte mp3Volume = 10;              // 0 to 30
const int numTracks = 4;
int TriggerCount = 0;

SoftwareSerial mySoftwareSerial(rxPin, txPin);            //RX, TX
DFRobotDFPlayerMini myDFPlayer;

void setup() {

  gpio_init();

  pinMode(pirPin, INPUT);
  pinMode(standbyPin, INPUT_PULLUP);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  startSerial();                          // start Serial and MySoftwareSerial
  startMP3();                             // start DFPlayer Mini MP3

  triggerBaseline = millis();

  if (digitalRead(standbyPin) == LOW) {   
    standbyMode();
  }
  triggerBaseline = millis();
}

void loop() {

  Serial.print("Time to sleep: " );
  Serial.print(sleepDelay - ((millis() - triggerBaseline) / 1000));
  Serial.println("s");

  Serial.print("PIR state: " );
  Serial.println(digitalRead(pirPin));
  Serial.print("justAwoke state:" );
  Serial.println(justAwoke);
  Serial.println();


  while (digitalRead(pirPin) == HIGH || justAwoke == true) {
    Serial.println("Checkpoint A");
    justAwoke = false;
    TriggerCount++;
    Serial.println("");
    Serial.println("Motion triggered");

    int Track = random(1, numTracks);
    Serial.print("Track: ");
    Serial.println(Track);

    myDFPlayer.play(Track);
   
    for (int i = 0; i <= 5; i++) {

      long OnTime = random(100, 1500);
      long OffTime = random(100, 1500);
      digitalWrite(ledPin, HIGH);
      delay(OnTime);
      digitalWrite(ledPin, LOW);
      delay(OffTime);
    }
    digitalWrite(ledPin, HIGH);
    triggerBaseline = millis();
  }

  // **** SLEEP TIMER ***

  if ((millis() - triggerBaseline) / 1000 >= sleepDelay && digitalRead(pirPin) == LOW) {
   
    for (int i = 0; i <= 5; i++) {              // rapdid pulse led
      digitalWrite(ledPin, LOW);
      delay(300);
      digitalWrite(ledPin, HIGH);
      delay(300);
    }

    sendReport();
    stopMP3();
    //stopSerial();
    digitalWrite(ledPin, LOW);
    Serial.println("Entering Light Sleep.");
    delay(2000);                               
    lightSleep();                              // put esp8266 in Light Sleep Mode
    delay(2000);

    wakeUp();
  }
  delay(1000);

}

void stopSerial () {
  Serial.println("Stopping serial and entering Light Sleep...");
  delay(500);
  Serial.flush();
  delay(500);
  Serial.end();

}

void startSerial() {

  Serial.begin(115200);
  while (!Serial) {
  }
  Serial.println("");
  Serial.println("Serial started.");
}

void stopMP3 () {
  Serial.println("Stopping MP3...");
  //mySoftwareSerial.flush();
  delay(1000);
  mySoftwareSerial.end();
  //digitalWrite(miniFETpin, LOW);            // cut MP3 power
  Serial.println("MP3 stopped.");
}

void startMP3() {
  Serial.println("Starting MP3...");
  mySoftwareSerial.begin(9600);                                           //Initialize DLPlayer on software serial connection

  Serial.println("Checkpoint 1");

  if (!myDFPlayer.begin(mySoftwareSerial, false)) {
    Serial.println("Unable to begin:");
    Serial.println("1.Please recheck the connection!");
    Serial.println("2.Please insert the SD card!");

    while (true) {
      Serial.println("Starting MP3 Module...");
      delay(0);                                                           // Code to compatible with ESP8266 watch dog.
    }
  }
  Serial.println("MP3 started.");
  myDFPlayer.volume(mp3Volume);
  Serial.println("MP3 volume set.");
}

void lightSleep() {

  wifi_station_disconnect();
  wifi_set_opmode_current(NULL_MODE);
  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T);     
wifi_set_sleep_type()
  wifi_fpm_open();                                                     
  gpio_pin_wakeup_enable(GPIO_ID_PIN(5), GPIO_PIN_INTR_HILEVEL);         
GPIO_PIN_INTR_HILEVEL
  delay(200);
  wifi_fpm_do_sleep(0xFFFFFFF);                                       
  delay(200);
}

void wakeUp() {

  //startSerial();
  digitalWrite(ledPin, HIGH);
  Serial.println("");
  Serial.println("Just woke up!");

  startMP3();
  justAwoke = true;                                                       // Trigger alarm upon wake up

  triggerBaseline = millis();                                             //reset awake timer
}

void sendReport() {
  Serial.println("");
  Serial.println("Sending report...");

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.println("");
  Serial.print("Connecting to WiFi");

  long WiFiBaseline = millis();

  while (WiFi.status() != WL_CONNECTED && (millis() - WiFiBaseline) / 1000 < WiFiTimeout) {
    delay(500);
    Serial.print(".");
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("");
    Serial.print("WiFi connected");

    //  *** Reserved for Connect and send to Adafruit IO
       
  }
  else {
    Serial.println("");
    Serial.print("WiFi connection failed");
  }

  Serial.println("");
  Serial.println("Report sent.");
}

void standbyMode() {
  Serial.println("Checkpoint 3");

  long standbyBaseline = millis();
  while ((millis() - standbyBaseline) / 1000 < standbyDelay) {
    digitalWrite(ledPin, HIGH);
    delay(500);
    digitalWrite(ledPin, LOW);
    delay(1000);
  }
}


Re: Light Sleep with DFPlayer and PIR module

PostPosted: Sat Feb 20, 2021 2:07 pm
by StanJ
Light sleep doesn't work very well with the current Arduino core. I played with it (rather a lot) last year, and found that when it goes to Light Sleep it stops ALL of the timers. It doesn't automatically restart them all when it comes out of sleep; it doesn't keep track of what it disabled. To make it work correctly the core needs to scan the struct of timers, save that off somewhere (maybe in RTC RAM) and then go to Sleep, and restore the timers again upon coming out of Sleep.

I'm nowhere near good enough at C or C++ to figure out how to correct it in the core. I asked for help, but nobody has stepped up to the plate. I know they got it working for the NodeMCU Lua, but there were ~ 2,000 different changes in that massive pull request, and seeing how they've done it is impossible for me. I tried. ;-)

Automatic Light Sleep works OK, but it doesn't get down to the low current levels you get with the two Forced Light Sleep modes.

Re: Light Sleep with DFPlayer and PIR module

PostPosted: Wed Feb 24, 2021 9:51 am
by DSKUP
Hey, thanks for the reply. Though I wish you had better news to share, I do appreciate you taking the time to comment. Hopefully someone will stumble upon this thread and have a magical work around.

Re: Light Sleep with DFPlayer and PIR module

PostPosted: Wed Feb 24, 2021 5:38 pm
by DSKUP
Through trial and error, I finally stumbled upon a solution. By simply adding the following as the first line of wakeUp(), it now behaves as it should. I guess having the interrupt enabled to wake from light sleep when it is not in light sleep was interfering with the normal function on that pin. Sometimes the answer is right in front of your nose.

gpio_pin_wakeup_disable();