Pulse counter - reducing battery usage

Hi all,
my question is not too Blynk related, but the project uses Blynk and this is the best community i know for esp tinkering :stuck_out_tongue:

So, i have this simple pulse counter that is reading the led pulses from my house energy meter and giving me a power reading and a total energy value.

It’s working on a battery and what i had was a 10000mAh power bank and an ESP-based board with usb input, which does the job though with a lot of conversion inefficiency.
The combination lasts me about 5 days.

I’m trying to use MODEM_SLEEP, but it seems ineffective and, with a 40% conversion inefficiency and assuming 10000mAh is accurate for the battery, the esp is requesting on average a little less than 40mA.

I’ve tried to implement light sleep and failed, but i couldn’t actually find any definitive answer on whether micros() actually works when using light sleep, or how i can ensure steady wake-ups on pulses and light sleeping in between.

Can anyone suggest a way to save more power than the following code does?

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

// Blynk Token
char auth[] = "----";

// WiFi credentials.
char ssid[] = "----";
char pass[] = "----";

BlynkTimer timer;

uint32_t t;
uint32_t t_prev;

uint32_t count;
uint32_t count_yesterday;

float power;

bool reset_armed = false;

void setup()
{
  WiFi.hostname("Contatore");
  WiFi.mode(WIFI_STA);
  WiFi.setSleepMode(WIFI_MODEM_SLEEP, 0);
  WiFi.begin(ssid, pass);

  ArduinoOTA.setHostname("Contatore");
  ArduinoOTA.begin();

  Blynk.config(auth, "claudiospinella.homepc.it", 8442);

  t = micros();
  t_prev = t;

  pinMode(14, INPUT);
  attachInterrupt(digitalPinToInterrupt(14), handleInterrupt, FALLING);

  timer.setInterval(5000, timed);
}

void loop()
{
  Blynk.run();
  timer.run();
  delay(250);
}

void handleInterrupt() {
  t = micros();
  if ((t - t_prev) > 20000) {
    count++;
    power = 3 * power / 4 + (360000000.0 / (t - t_prev) - power) / 4;
    t_prev = t;
  }
}

void timed() {
  Blynk.virtualWrite(V1, ((double) count) / 10000);
  Blynk.virtualWrite(V2, power);
  ArduinoOTA.handle();
}

BLYNK_CONNECTED() {
  Blynk.syncAll();
}

//Recover total energy from server
BLYNK_WRITE(V1) {
  count = (int) 10000 * param.asDouble();
}

//Arm the reset button
BLYNK_WRITE(V3) {
  reset_armed = param.asInt() > 0;
}
//Reset total consumption if armed
BLYNK_WRITE(V4) {
  if (param.asInt() > 0 && reset_armed) {
    count = 0;
  }
}

//Trigger daily energy recap
BLYNK_WRITE(V5) {
  if (param.asInt() > 0) {
    Blynk.virtualWrite(V6, ((double)(count - count_yesterday)) / 10000);
    Blynk.virtualWrite(V7, count);
    Blynk.virtualWrite(V5, 0);
  }
}

//Recover total as per the last daily recap
BLYNK_WRITE(V7) {
  count_yesterday = (unsigned int) param.asLong();
}

Maybe useful detail: the pulse counter is giving me a LOW pulse of roughly 5-10ms duration.

maybe I’m wrong,but you are not using deepsleep, only WiFi.setSleepMode

  • MODEM_SLEEP : 4 mA
  • LIGHT_SLEEP : < 2 mA
  • DeepSleep : < 0.25 mA

As mentioned, i’m currently using automatic modem sleep, and trying to get light sleep to work if at all possible.

Those can keep the connection to WiFi alive by waking up the radio hardware for the periodic DTIM packages, while deep sleps needs to reconnect every single time.

Therefore, deep sleep is not what i’m trying to do.

so, there is no other choice to reduce energy consumption.
my power bank is 10000mA too, and works less than one month in deepsleep mode,
and only 5 days in light sleep.
I got a Solar Power Bank, to replace it. :wink:

Well, the same bank works for 2 weeks in another project where i use light sleep, but here i can’t seem to find a way to make it work without breaking the counting

I don’t think that using Blynk in the normal way is going to work.
Clearly you can’t use deep sleep, otherwise you’d miss the flashed from the LED on the meter.
Turning off the Wi-Fi modem will save power, but having Blynk.run in the void loop won’t work.

I’d say that you should look at doing a timed connection to Blynk, say every hour, to upload the consumption data since the last connection. You’d use Blynk.connect / disconnect for this.

There doesn’t seem to be much point in having OTA in there either, as most of the time Wi-Fi will be off.

Pete.

1 Like

Hmm… those are good points, though i kinda like having the update every 5 seconds, and i have other cases where blynk.run done in a small burst every 2 seconds is working quite ok with light sleep. I would be happy if i could achieve light sleep in that 250ms delay that is in the loop.

OTA is to be discarded indeed, it’s practically useless since the poor wifi reception often leads to errors in the upload.

i have an idea how i could get it to work, by removing the interrupt and setting a wakeup pin and having a simple loop that would amount to:
-add 1 to the counter
-get current microseconds value
-calculate power
-save microseconds value for the next run
-update blynk if it is time to do so
-go to lightsleep until the next pulse

this could be allowed by the gpio_pin_wakeup_enable function, but it can only work if i have a way to get the current microseconds time, which i’m not sure is the case for light sleep

There’s another project around where an Arduino nano or similar is used to count the pulses and the esp8266 is used only to send the data via AT, that would change your battery consumption drastically

Found it Autonomous impulse counter for water meters (attiny85 + esp-01)

That’s also an interesting solution, though it reconnects every time (making frequent updates not practical) and is still more complex than would be necessary if micros() works with light sleep and can be made to last until the next input while keeping the connection alive.

I would be happy to gain a few days and curious to see if it’s possible while keeping the current functionality and hardware, but it’s not that vital to have it last for months :slight_smile:

  1. NodeMCU and same ESP boards with USB is bad for autonomous devices, cause consume a lot of energy and have bad voltage regulators. There are a lot of good regulators

  2. If you need to send data less than 20 minutes:
    a) use deepsleep mode with wake up by ESP reset pin
    b) use static IP address
    Your loop time will be less than 1 second. See my log
    700ms (!)
    note: ESP-01 don’t support wake up by timer (you should solder wire)

  3. ‘timer.setInterval’ doesn’t work in deepsleep mode and I think in lightsleep too.
    If you need send data every 5 seconds, use ESP.deepsleep(5000000, mode)
    Article

ESP.deepSleep(microseconds, mode) will put the chip into deep sleep. mode is one of 
WAKE_RF_DEFAULT, WAKE_RFCAL, WAKE_NO_RFCAL, WAKE_RF_DISABLED.
 (GPIO16 needs to be tied to RST to wake from deepSleep.)

See datasheet:

3.3. External Wake-up
During Light-sleep, the CPU is suspended and will not respond to the signals and interrupts
from the peripheral hardware interfaces. Therefore, ESP8266 needs to be woken up via
external GPIO. The waking process is less than 3 ms.
The GPIO wake-up function can only be enabled by level triggers. The interface is as
follows.

void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state);

4.3. External Wake-up
In Deep-sleep mode, the chip can be woken up and initialized by a low-level pulse
generated on the EXT_RSTB pin via an external IO.

So, external interrupt works only in Light sleep mode.

1 Like

check the guy with Swiss accent videos
he has greet videos on low power ESP8266