-->
Page 1 of 3

Light Sleep using more current than Modem Sleep

PostPosted: Wed Mar 09, 2016 7:47 am
by PaulRB
Hi all, I am experimenting with Light Sleep on my WeMos D1-mini (=ESP-12E)

My application is a weather station with wind speed, direction & rain sensors, all cheap mechanical sensors containing reed switches & magnets, I'm sure you've come accross them, if not, look here.

I would like to run the circuit from battery power, so looking to reduce current down to ideally around ~1mA on average if possible. The ESP would monitor the sensors for around 15 mins, then transmit the results to a web server in a few seconds.

I can't afford to make use of Deep Sleep, I believe, because the sensors need to be monitored almost continuously. In particular, the wind speed sensor could change every 2~3ms in very high winds. The rain sensor's pulses can last only a few tens of milliseconds, so I must be careful not to miss those. The wind direction sensor needs to be read several times per second and averaged, because it can swing around a lot in low to moderate winds.

I have sucessfully trialled Modem Sleep. This uses a very steady 15mA. I would ideally like to get down to around one tenth of that to extend battery life.

So I am now trialling Light Sleep, which, according to all the confusing documentation I have seen on Expressif's website and other places, should get me down to less than a couple of mA.

I believe I have Light Sleep working, but it is not performing as well as hoped. The reason I believe I have Light Sleep working, is because I have a delay(2) at the end of main(). Without this delay(), the current consumption is quite steady at 75mA. With the delay(), the current varies between 19mA with peaks of 30~60mA every second or two. Its hard to be sure what exactly is going on using my multimeter. I don't have easy access to a 'scope.

So Light Sleep is consuming more than Modem Sleep at the moment. I would like to achieve a couple of mA or less.

If anyone unfamilliar with WeMos D1-mini is concerned about the consumption of the other components, I have built other circuits, temp/humidity sensors, which make use of Deep Sleep, and the consumption of the whole circuit is around 180uA.

Please can anyone suggest ways to reduce the current of my weather sensors circuit? My current test code is shown below. Currently it reports the readings only over serial. Eventually they will be transmitted to a server. I have that part worked out from building my other sensors.

My plan B is to use an ATtiny 84 or 85 to continuously monitor the sensors and communicate with the ESP chip over i2c, with the ESP spending most of its time in Deep Sleep.

Thanks,

Paul

Code: Select all/*
 * WeMos D1-mini Weather Station
 * PaulRB
 * March 2016
 */

#include <ESP8266WiFi.h>

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

#define WIND_DIR_SENSOR   A0
#define WIND_SENSOR_ENABLE  D5
#define WIND_SPEED_SENSOR  D3
#define RAIN_SENSOR  D7
#define LED_BUILTIN D4

long windDirTot;
int windDirCount;
int windDirPrev;
unsigned long lastWindDirTime;

int windSpeedCount;
int windSpeedSensorPrev;
unsigned long lastWindSpeedTime;

int rainCount;
int rainSensorPrev;

unsigned long lastReportTime;

const int reading[] = {158, 183, 221, 297, 387, 459, 556, 652, 741, 812, 850, 904, 945, 975, 1007, 1023};
const int compass[] = {292, 247, 270, 337, 315,  22,   0, 202, 225,  67,  45, 157, 180, 112,  135,   90};

const char ssid[]     = "sss";
const char password[] = "ppp";
const char host[]     = "www.xxx.co.uk";

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

  pinMode(WIND_SPEED_SENSOR, INPUT_PULLUP);
  pinMode(RAIN_SENSOR, INPUT_PULLUP);
  pinMode(WIND_SENSOR_ENABLE, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  WiFi.mode(WIFI_STA);
  wifi_fpm_set_sleep_type(LIGHT_SLEEP_T); // seems to make no difference
  //wifi_set_sleep_type(LIGHT_SLEEP_T); // also seems to make no difference
  WiFi.begin(ssid, password);

  int retries = 0;
  while (WiFi.status() != WL_CONNECTED && ++retries < 60) {
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi connection failed");
  }
  else {

    Serial.println("OK");
    Serial.print("WiFi connected, IP address: ");
    Serial.println(WiFi.localIP());
  }

  //WiFi.forceSleepBegin(); // reduces current to 15mA

}

void loop() {

  unsigned long timeNow = millis();

  // Time to check wind speed sensor?
  if (timeNow - lastWindSpeedTime >= 2) {
    lastWindSpeedTime += 2;

    // Check wind speed sensor
    int windSpeedSensor = digitalRead(WIND_SPEED_SENSOR);
    if (windSpeedSensor != windSpeedSensorPrev) {
      // Sensor has changed
      windSpeedCount++;
      windSpeedSensorPrev = windSpeedSensor;
    }

    // Check rain sensor
    int rainSensor = digitalRead(RAIN_SENSOR);
    if (rainSensor != rainSensorPrev) {
      // Sensor has changed, count falling edges only
      if (rainSensor == LOW) rainCount++;
      rainSensorPrev = rainSensor;
    }

    // Time to check wind direction sensor?
    if (timeNow - lastWindDirTime >= 100) {
      lastWindDirTime += 100;

      // Enable sensor only to take reading. Reduces current
      digitalWrite(WIND_SENSOR_ENABLE, HIGH);
      int readingNow = analogRead(WIND_DIR_SENSOR);
      digitalWrite(WIND_SENSOR_ENABLE, LOW);
      // Translate analog reading into compass direction
      // Can be one of 16 values, but there could be some
      // analog noise, so the reading[] array contains values
      // mid-way between the possible readings.
      int i;
      for (i = 0; i < 16 && readingNow >= reading[i]; i++);
      int windDirNow = compass[i];
      // Check if sensor has swept through 0 degrees, moving in either direction
      if (windDirNow - windDirPrev > 180) windDirNow -= 360;
      if (windDirPrev - windDirNow > 180) windDirNow += 360;
      // Update total and count of data points for calculating average
      windDirTot += windDirNow;
      windDirCount++;
      windDirPrev = windDirNow;
    }

    // Time to send sensor readings?
    unsigned long reportPeriod = timeNow - lastReportTime;
    if ( reportPeriod >= 5000) {
      lastReportTime += 5000;

      digitalWrite(LED_BUILTIN, LOW);
      // Calculate average wind direction over the reporting period
      int windDir;
      if (windDirCount > 0) windDir = windDirTot / windDirCount; else windDir = 0;
      while (windDir >= 360) windDir -= 360;
      while (windDir < 0) windDir += 360;
      Serial.print("WindDir=");
      Serial.print(windDir);
      // Zero the count & total for next period
      windDirTot = 0;
      windDirCount = 0;

      // Calcualate average wind speed over reporting period
      // Note: 1 rotation per second = 2.4 Km/hr
      // 4 counts per rotation, so 1 count per millisecond = 600 Km/hr
      // To-do: calculate highest wind gust (over 6s period) during period
      unsigned long windSpeed;
      if (reportPeriod > 0) windSpeed = 600UL * windSpeedCount / reportPeriod; else windSpeed = 0;
      Serial.print(" WindSpd=");
      Serial.print(windSpeed);
      // Zero wind speed sensor count for next period
      windSpeedCount = 0;

      // Report rain guage count
      // To-do: convert this to mm/hr
      Serial.print(" rain=");
      Serial.print(rainCount);

      Serial.println();
      digitalWrite(LED_BUILTIN, HIGH);
    }
  }
  delay(2); // Reduces current from steady 75mA to varying 19mA~75mA
}


Re: Light Sleep using more current than Modem Sleep

PostPosted: Wed Mar 09, 2016 2:21 pm
by schufti
on the espressif bbs one can read on the "light sleep":
During Light-Sleep, the CPU may be suspended in applications like Wi-Fi switch. Without data transmission, the Wi-Fi Modem circuit can be turned off and CPU suspended to save power

so, who suspends the CPU? Is there an api_call for? I don't think that delay() does "suspend".
And: once cpu is suspended, who will do a "resume"?

From the description on espressiv bbs to me it looks like the whole light-sleep only is feasible in conection with wifi-sta, suspending cpu and powering down modem when there is no datatransfer, only resuming on the next DTIM to check if there is data waiting to be delivered...

n.b.: don't forget to switch of serial output. The serial-usb converter uses quite some power,too. It will usually power down if no transfer.

Re: Light Sleep using more current than Modem Sleep

PostPosted: Wed Mar 09, 2016 3:48 pm
by PaulRB
schufti wrote:so, who suspends the CPU? Is there an api_call for? I don't think that delay() does "suspend".
And: once cpu is suspended, who will do a "resume"?

From the description on espressiv bbs to me it looks like the whole light-sleep only is feasible in conection with wifi-sta, suspending cpu and powering down modem when there is no datatransfer, only resuming on the next DTIM to check if there is data waiting to be delivered...

Well, adding/removing the delay() definitely makes a difference to the current consumption, just nowhere near as much as i hoped. And i am using station mode. Perhaps the delay() makes it clear to the RTOS that nothing needs to be done, versus no delay, where it might look like the user's sketch is busy all the time.
schufti wrote:n.b.: don't forget to switch of serial output. The serial-usb converter uses quite some power,too. It will usually power down if no transfer.

I'll give that a try and report my findings. Thanks @schufti

Re: Light Sleep using more current than Modem Sleep

PostPosted: Wed Mar 09, 2016 4:05 pm
by schufti
ha, i knew I had an espressiv document on sleep functions somwhere. Found it.
Haven't looked into it right now but maybe it is of some help?