HTCC-AB01 drains 1000mAh battery in 1 day

Besides LoraWAN issues I’ve described in separate thread, I have one more problem with my HTCC-AB01 sensor, pictued here:

The problem is it drains whole 1000mAh 3,7V LiPo battery in almost one day.
I transmit sensor state only every hour.
And every hour battery level seems to be ~1-2% lower.

Here is my current code:

And here how payload looks in the LoraWAN app console through the day:

I thought that the device is put to sleep between transmission and 1000mAh battery would last months, not hours :confused:

You can increase this time.

Please measure the current when it sleep.

delay(40000); is too long, It is recommend add one more state and force sleep when waiting.

not sure is it need LowPower_Handler()

Quency-D, I will increase later to 24h, but for now I need to monitor battery drain

@ksckung Thanks, I didn’t know USB port is active after disconnecting it. I will try with rebooting the board after USB disconnect. I will also try to measure the current, but I have no spare JST plug right now

Btw, I test now with board rebooted after USB disconnect and for first two hours BatteryVoltage was the same but I see battery level change:

How come is that? Battery level is just a voltage mapped to a range…

That last issue solved. I used twice highByte for batteryVoltage.

I have not connected militmeter yet, but with the board reset after USB disconnect I get:

  • about 1% of battery level drained every 3 or 4 hours (3 or 4 hourly transmission)
  • that means that theoretically 100% of battery would last for 300-400 hours / transmission
  • this means ~12-16 days

Is this normal for a 1000mAh LiPo battery?
I expected much longer battery time as many other wireless sensors with smaller battery last for months.

It depends on how frequency your device wakes up, sample and send the data.
My CubeCell – Dev-Board wake up every 1min, sample HDC1080 temperature and humidity, sample battery voltage, and send the data via Lora.
The average current consumption is ~109uA. Where 6.3uA in deepsleep, very short 150mA peak when sampling+Lora.

Using 1000mAh battery, it can operate around 1 year.

1 Like

No that’s not normal, it sounds like it’s not going to sleep properly or waking up too often, or something is staying powered up (sensor?).

You can printf debug this while USB attached e.g. log at loop() start, and before the LoRaWAN.sleep(); (and the log messages should stop with the last sleep).

If it’s not that, then look for pins kept HIGH without resistors?

@ksckung, @bwooce

I’ve finally connected a multimeter and here are the results:

  • after the device boots, it takes 1,34 mA
  • when I disconnect a reed switch (simulating letterbox mail slot or door open) the usage goes up to 11,08 mA and it stays that for about 2 minutes (value of my timer)
  • then it returns back to 1,34 mA until next reed switch open or hourly transmission

This is measured with a simple Uni-T UT120c multimeter.

So, I believe I should get uA-level values in LoRaWAN.sleep state, right?
I now get battery life ~14 days, but I’d rather have lot longer, obviously.

I’m not a skilled programmer, how can I debug it?
Here’s the current code:

I seem to remember the reset button not being enough to turn off the USB side, try a power cycle then repeat the tests? I’ll admit to never delving deeply into the power consumption side, but others on this forum have and there are threads about it (you’re not using Vext but maybe turning it off is a good defensive measure too, as one example).

That 11mA might be the cost of the delay() CPU burn loop…last time I looked there was some yield()'s in the implementation but it was a busy-loop (rather than sleeping). Alternatively, wow, those GPIOs are supplying a lot of current. Maybe the pull-up resistors didn’t engage? You can double-check/ensure they are by digitalWrite(pin, HIGH); to them.

I’ve expanded your code a little, but not tested it at all (!!), here. The main change is to remove the delay(), I’m impressed the stack continues ~working with the delays you had in there, some background processing continues but I’m unclear if it stays healthy - it’s much better to let loop() complete ASAP. It should send packets on both open & close if they’re more than a minute apart.

As you saw on the TTN thread, retransmitting while the radio is in use won’t work, and in fact I think you should reconsider transmitting on each open & close. I put some code in there to limit to a max of one send per minute, it may even be better (but more complicated) to log the open and then after n(60?) seconds transmit the current state - you would effectively send one packet with “it opened and then closed/stayed open” type of information. Doing it like that accounts for things like wind with a half-open door flickering open/closed over and over. That’ll burn through your battery quickly.

Anyway, my code is just another way of extending it and I’m not 100% sure I got the open/close state the right way around, and almost certainly didn’t get the door vs mailslot GPIOs correct. It was a fun distraction on a Sunday night though.

Keep going, you’re almost there.

Please use the original code and hardware to verify it sleep at the uA level first.

getBatteryVoltage(); may turn on the PMOS of voltage divider, please check is it turn off after sampling.

Please measure the current through the reed switch, use a higher pull-up resistor insert of an internal pullup. It should be better if it can pullup only when you needed.

DEVICE_STATE_SLEEP is for sleep, not for TX.

When it wakeup, It wastes 120000+nx100+1000 ms before the next sleep. Change it into a switch case and change appTxDutyCycle sleep time between checking.
Case 0: //send Lora
Case 1: // sleep 120000ms
Case 2: // check sensor pin, until both low. Sleep 100ms
Case 3: //sleep 1000ms
Case 4: // send Lora, Sleep as normal.

1 Like

@bwooce Thank you VERY MUCH for your input and for the updated code.
It works perfectly and in fact works both ways (if the interval is longer than 1 minute).
I will probably go the way you suggest in the future and log the events to send them in package.
But for now it just works.

But what is more important: your code allowed me to identify what causes power drain.
Reed switches are.

  • When both reed switches are closed (pin shortcut to ground) power usage is 1.34mA
  • When one reed switch is open - power usage in deep sleep if half of this (~677uA)
  • When both reed switches are open - power usage in deep sleep is 9.4uA (PERFECT!!!)

So, going with the advice from @ksckung (THANK YOU TOO!!!), I changed INPUT_PULLUP mode to INPUT and attached resistors between 1 & 2 pins and a 3.3V pin. I’ve never been making a pullup so I’ve been guessing here: tried different resistors (1K, 10K, 100K) and I got best results on 100K.
And the results (after the boards goes to sleep) are:

  • 75uA when two reed switches are closed
  • 42uA when one reed switch is open
  • 9.4uA when both reed switches are open

So I is quite good now, but still not perfect.
What shall I do to lower power usage even more?

  • use ever larger resistors? what Ohm?
  • perhaps I should find reed switches of different logic? (NO?)

PS. I’m leaning towards using NO reed switches and keeping 100K resistors to keep power usage low during switch open (circuit closed). Good direction?

1 Like

Using internal pull-up
Using 100k
Yes, you can select an even higher value, i.e. 1M~4M7, just measure and make sure the voltage on that input pin is higher than 2.0V (voltage input high).
If the input logic can modify, It is possible to connect the reed switch to 3V3 with a pull-down resistor.
In this case, the input pin will not consume power when the switch is open.

1 Like

Thank you!
I’ve kept 100K pullup resistors but used NO reed switches instead of NC. It works perfectly now!
Most of the time power usage is below 10uA, only when there is some mailbox door movement it goes to ~40uA for a second to transmit and than returns to ~9uA. I’ve been testing whole day and battery hasn’t lost a single percent! I believe it will work now for a year or more.

Thank you guys again, you helped me solve all issues.

1 Like

I would love to here about an update to your project, if you’re willing, because I am embarking on the same sort of thing myself. In my case, my post-box is about 150 meters away, 35 meters down a hill. I did a range test while running the example “pingpong” script and, well, I think because it’s not exactly line-of-sight, I wasn’t able to reach the mailbox on the default power level. I’ll be playing with it more over the next few days.

I’d love to here from you, not only just about power and battery life, but how did the reed switches work out? Are you still using the system? What other pitfalls, if any, did you come across since July?

I would like to ask the information in the payload, how do you write batterylevel?
I will only display the value in hexadecimal

here is my code, i hope this helps.

/*  get the BatteryVoltage in mV. */
uint16_t BoardGetBatteryVoltage(void)
    float temp = 0;
    uint16_t volt;
    uint8_t pin;
    pin = ADC;
#if defined(CubeCell_Board) || defined(CubeCell_Capsule) || defined(CubeCell_BoardPlus) || defined(CubeCell_BoardPRO) || defined(CubeCell_GPS) || defined(CubeCell_HalfAA)
     * have external 10K VDD pullup resistor
     * connected to VBAT_ADC_CTL pin
    pinMode(VBAT_ADC_CTL, OUTPUT);
    digitalWrite(VBAT_ADC_CTL, LOW);
    for (int i = 0; i < 50; i++) // read 50 times and get average
        temp += analogReadmV(pin);
    volt = temp / 50;
#if defined(CubeCell_Board) || defined(CubeCell_Capsule) || defined(CubeCell_BoardPlus) || defined(CubeCell_BoardPRO) || defined(CubeCell_GPS) || defined(CubeCell_HalfAA)
    pinMode(VBAT_ADC_CTL, INPUT);
    volt = volt * 2;
    return volt;

    #define BATTERY_MAX_LEVEL 4100      // 4.1       // mV 3600 for saft LS17500 and 4100 for lithium
    #define BATTERY_MIN_LEVEL 3400      // 3.4       // mV 2400 minimum for saft LS17500 and 3.4 minimum for lithium
    #define BATTERY_SHUTDOWN_LEVEL 3300 // 3.31 // mV 2300 minimum for saft LS17500 and 3.3 minimum for lithium

        #define BATTERY_LORAWAN_MAX_LEVEL 254
        #define BATTERY_LORAWAN_EXT_PWR 0
        static uint16_t BatteryVoltage = BATTERY_MAX_LEVEL;

         uint8_t BoardGetBatteryLevel(void)
            uint8_t batteryLevel = 0;
            BatteryVoltage = BoardGetBatteryVoltage();
            if (GetBoardPowerSource() == USB_POWER)
                batteryLevel = BATTERY_LORAWAN_EXT_PWR ;
                if (BatteryVoltage >= BATTERY_MAX_LEVEL)
                    batteryLevel = BATTERY_LORAWAN_MAX_LEVEL;
                else if ((BatteryVoltage > BATTERY_MIN_LEVEL) && (BatteryVoltage < BATTERY_MAX_LEVEL))
                    batteryLevel =
                        ((253 * (BatteryVoltage - BATTERY_MIN_LEVEL)) / (BATTERY_MAX_LEVEL - BATTERY_MIN_LEVEL)) + 1;
                else if ((BatteryVoltage >= BATTERY_SHUTDOWN_LEVEL) && (BatteryVoltage <= BATTERY_MIN_LEVEL))
                    batteryLevel = 1;
                else // if( BatteryVoltage <= BATTERY_SHUTDOWN_LEVEL )
                    batteryLevel = BATTERY_LORAWAN_UNKNOWN_LEVEL;
            return batteryLevel;