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