[GH-ISSUE #76] Maximize battery life #61

Closed
opened 2026-05-07 00:19:23 +02:00 by BreizhHardware · 22 comments

Originally created by @karmanyaahm on GitHub (Dec 31, 2021).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/76

Having something like the following would be very cool, though it might be difficult to build. Basically:

  1. Detect that the device is on a new network (based on SSID, mobile data status, etc)
  2. The device calls the subscribe URL (/json or /sse) with ?keepalive=test
  3. The server sends keepalives at a known increasing interval, 30s, 35s, 40s, 45s ...
  4. At some point (say 90 sec), the client no longer receives the keepalive on time - it detects that the connection was disrupted.
  5. Next, it can connect to the server with ?keepalive=85 and receive keepalives every 85s.
  6. This information can be cached per SSID/mobile data/etc for some time.
Originally created by @karmanyaahm on GitHub (Dec 31, 2021). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/76 Having something like the following would be very cool, though it might be difficult to build. Basically: 1. Detect that the device is on a new network (based on SSID, mobile data status, etc) 2. The device calls the subscribe URL (/json or /sse) with ?keepalive=test 3. The server sends keepalives at a known increasing interval, 30s, 35s, 40s, 45s ... 4. At some point (say 90 sec), the client no longer receives the keepalive on time - it detects that the connection was disrupted. 5. Next, it can connect to the server with ?keepalive=85 and receive keepalives every 85s. 6. This information can be cached per SSID/mobile data/etc for some time.
Author
Owner

@binwiederhier commented on GitHub (Dec 31, 2021):

Good Reference: https://github.com/gotify/server/issues/343

<!-- gh-comment-id:1003289146 --> @binwiederhier commented on GitHub (Dec 31, 2021): Good Reference: https://github.com/gotify/server/issues/343
Author
Owner

@binwiederhier commented on GitHub (Jan 1, 2022):

I'm going to use this ticket to work on battery optimization for various things. Here's a few things I've identified:

  • The 30s keepalive is too short. Increase to 65s. (server side)
  • The hourly Firebase keepalive is not necessary. Increase to every 3 hours. (server side)
  • Polling every 15 minutes is not necessary if the socket didn't break (or at all)
  • The AutoRestartWorker and the PollWorker (both every 15 minutes) should be combined and the frequency should be reduced
  • Investigate Linux TCP keepalive settings (see link above)
  • Investigate Websockets (Gotify)
  • Do some Wiresharking
  • Investigate dynamic keepalive (see suggestion above)
  • Look into why coroutines still run when app is not in foreground: D/NtfyDetailActivity: Checking global and subscription-specific 'muted until' timestamp
  • SubscriberConnection: Find a better way to check for the broken connection (delay+printlog loop)
<!-- gh-comment-id:1003622144 --> @binwiederhier commented on GitHub (Jan 1, 2022): I'm going to use this ticket to work on battery optimization for various things. Here's a few things I've identified: - [x] The 30s keepalive is too short. Increase to 65s. (server side) - [x] The hourly Firebase keepalive is not necessary. Increase to every 3 hours. (server side) - [x] Polling every 15 minutes is not necessary if the socket didn't break (or at all) - [x] ~The AutoRestartWorker and the PollWorker (both every 15 minutes) should be combined~ and the frequency should be reduced - [ ] Investigate Linux TCP keepalive settings (see link above) - [x] Investigate Websockets (Gotify) - [ ] Do some Wiresharking - [ ] Investigate dynamic keepalive (see suggestion above) - [ ] Look into why coroutines still run when app is not in foreground: `D/NtfyDetailActivity: Checking global and subscription-specific 'muted until' timestamp` - [ ] SubscriberConnection: Find a better way to check for the broken connection (delay+printlog loop)
Author
Owner

@binwiederhier commented on GitHub (Jan 2, 2022):

With the changes made in the unreleased Android version 1.5.2, my battery life has improved again. It's back to 4% for the day.

<!-- gh-comment-id:1003777529 --> @binwiederhier commented on GitHub (Jan 2, 2022): With the changes made in the unreleased Android version 1.5.2, my battery life has improved again. It's back to 4% for the day.
Author
Owner

@arminus commented on GitHub (Jan 11, 2022):

I'm on 1.5.2 (play) / Android 8.0.0 with my own server.

According to GSam Battery Monitor, Ntfy used 42 mins CPU time since the last recharge 8h ago, which would mean almost 9% for those 8 hours (I didn't have it open during that time and I didn't receive any messages).

Is that to be expected? Overall it contributes to 11,2% of spent power (double the 5,1% for the Android-System and e.g. 4,4% for Outlook)

<!-- gh-comment-id:1010194887 --> @arminus commented on GitHub (Jan 11, 2022): I'm on 1.5.2 (play) / Android 8.0.0 with my own server. According to GSam Battery Monitor, Ntfy used 42 mins CPU time since the last recharge 8h ago, which would mean almost 9% for those 8 hours (I didn't have it open during that time and I didn't receive any messages). Is that to be expected? Overall it contributes to 11,2% of spent power (double the 5,1% for the Android-System and e.g. 4,4% for Outlook)
Author
Owner

@binwiederhier commented on GitHub (Jan 11, 2022):

@arminus Thank you for providing numbers. That's very valuable.

It varies greatly, depending on your connection and phone. After attachments (#82), I'm going to look at improving battery life more, and make it more configurable. This is very very very tricky, because it's environment-dependent. What works for you may not work for others.

There are several strategies I'll try:

  • Increase keepalive (+ make configurable)
  • Make wake-lock configurable (off/on)
  • Switch to websockets (like gotify; possibly make configurable)

Should be only a week or so until I start work on this.

<!-- gh-comment-id:1010204693 --> @binwiederhier commented on GitHub (Jan 11, 2022): @arminus Thank you for providing numbers. That's very valuable. It varies greatly, depending on your connection and phone. After attachments (#82), I'm going to look at improving battery life more, and make it more configurable. This is very very very tricky, because it's environment-dependent. What works for you may not work for others. There are several strategies I'll try: - Increase keepalive (+ make configurable) - Make wake-lock configurable (off/on) - Switch to websockets (like gotify; possibly make configurable) Should be only a week or so until I start work on this.
Author
Owner

@binwiederhier commented on GitHub (Jan 11, 2022):

@arminus Few questions:

  • Is your home server in your LAN or Internet-accessible? i.e. does your phone have access to it all the time, or are there long periods of inaccessibility?
  • Did you move around on the day you tested this? Lots of network-hopping/driving?
<!-- gh-comment-id:1010228739 --> @binwiederhier commented on GitHub (Jan 11, 2022): @arminus Few questions: - Is your home server in your LAN or Internet-accessible? i.e. does your phone have access to it all the time, or are there long periods of inaccessibility? - Did you move around on the day you tested this? Lots of network-hopping/driving?
Author
Owner

@arminus commented on GitHub (Jan 11, 2022):

  • I have the server in my LAN and over those 8 hours today, I'd say it was maybe 1/3 not in that LAN
  • during that 1/3rd of the time, I was on mobile data, how much cell towers I met (while skiing ;-) I can't say
  • I'll monitor this tomorrow, should be in the house/LAN all day
<!-- gh-comment-id:1010250772 --> @arminus commented on GitHub (Jan 11, 2022): - I have the server in my LAN and over those 8 hours today, I'd say it was maybe 1/3 not in that LAN - during that 1/3rd of the time, I was on mobile data, how much cell towers I met (while skiing ;-) I can't say - I'll monitor this tomorrow, should be in the house/LAN all day
Author
Owner

@binwiederhier commented on GitHub (Jan 11, 2022):

Thanks for that info!!

I am pretty aggressively retrying when the connection is lost, basically every 60 seconds. But there are other horrible things I could improve.

<!-- gh-comment-id:1010355020 --> @binwiederhier commented on GitHub (Jan 11, 2022): Thanks for that info!! I am pretty aggressively retrying when the connection is lost, basically every 60 seconds. But there are other horrible things I could improve.
Author
Owner

@binwiederhier commented on GitHub (Jan 11, 2022):

Make wake lock optional: https://github.com/binwiederhier/ntfy-android/pull/10, thanks @MatMaul

<!-- gh-comment-id:1010447609 --> @binwiederhier commented on GitHub (Jan 11, 2022): Make wake lock optional: https://github.com/binwiederhier/ntfy-android/pull/10, thanks @MatMaul
Author
Owner

@arminus commented on GitHub (Jan 12, 2022):

So today my phone is lying on my desk with connection to the LAN my server is running on.

So far 40 minutes CPU time out of 380 minutes since the last charge, or a whopping 15,8% of total battery consumption. This is even worse than yesterday with 1/ no LAN access.

<!-- gh-comment-id:1011126692 --> @arminus commented on GitHub (Jan 12, 2022): So today my phone is lying on my desk with connection to the LAN my server is running on. So far 40 minutes CPU time out of 380 minutes since the last charge, or a whopping 15,8% of total battery consumption. This is even worse than yesterday with 1/ no LAN access.
Author
Owner

@binwiederhier commented on GitHub (Jan 12, 2022):

This is horrible and totally unacceptable. If you run nginx/apache/... in front of the ntfy server, you could try to find out if there is an excessive amount of requests happening. Other than that, you could connect adb+logcat to your phone, but I'm not sure how much you're set up with Android development.

I have been running @MatMaul's change for 4 hours today and it shows 0% battery usage. I've been able to get messages through even when the phone is sleeping, so that change is very very exciting.

@arminus If you like, I can build you an .apk with the wakelock change that you can install and try for yourself.

<!-- gh-comment-id:1011165840 --> @binwiederhier commented on GitHub (Jan 12, 2022): This is horrible and totally unacceptable. If you run nginx/apache/... in front of the ntfy server, you could try to find out if there is an excessive amount of requests happening. Other than that, you could connect adb+logcat to your phone, but I'm not sure how much you're set up with Android development. I have been running @MatMaul's change for 4 hours today and it shows 0% battery usage. I've been able to get messages through even when the phone is sleeping, so that change is very very exciting. @arminus If you like, I can build you an .apk with the wakelock change that you can install and try for yourself.
Author
Owner

@binwiederhier commented on GitHub (Jan 12, 2022):

0% for almost 6 hours.

<!-- gh-comment-id:1011298574 --> @binwiederhier commented on GitHub (Jan 12, 2022): 0% for almost 6 hours.
Author
Owner

@arminus commented on GitHub (Jan 12, 2022):

If you like, I can build you an .apk with the wakelock change that you can install and try for yourself.

gladly.

I have adb and an old SDK/Android DevStudo installed, but I forgot most of what I knew about Android dev a while ago... If you tell me what to do (or point me somewhere), I'll try, though...

<!-- gh-comment-id:1011304883 --> @arminus commented on GitHub (Jan 12, 2022): > If you like, I can build you an .apk with the wakelock change that you can install and try for yourself. gladly. I have adb and an old SDK/Android DevStudo installed, but I forgot most of what I knew about Android dev a while ago... If you tell me what to do (or point me somewhere), I'll try, though...
Author
Owner

@binwiederhier commented on GitHub (Jan 12, 2022):

Thank you for helping out. It means a lot.

apk

Here's the .apk: https://phil.nopaste.net/kVu2T0jdwA?d=1&f=app-play-debug.apk&a=3H9iMXMzwK
This is the latest main branch, which includes MatMaul's wake lock changes.

Install:

  1. Download the .apk file and install it. Note that this will upgrade the internal database schema of the ntfy App, meaning that you cannot go back to the prod version without losing subscriptions and notifications.
  2. Go to Settings -> Toggle "Persistent wakelock" to OFF

adb

  1. Turn on developer mode on your phone: Go to "Settings", then tap "About device" or "About phone". Scroll down, then tap "Build number" seven times.
  2. Go to Settings -> System -> Developer options, Turn ON "Wireless ADB debugging" and "Wireless debugging" (you may have to repeat this step every time you reconnect to the wifi)
  3. Install the Android Sdk, then run adb connect <yourphoneip>. It could say "connected" after you ACK it on your phone
  4. Then you should be able to do adb logcat --pid=$(adb shell pidof -s io.heckel.ntfy)
<!-- gh-comment-id:1011335477 --> @binwiederhier commented on GitHub (Jan 12, 2022): Thank you for helping out. It means a lot. ## apk Here's the .apk: https://phil.nopaste.net/kVu2T0jdwA?d=1&f=app-play-debug.apk&a=3H9iMXMzwK This is the latest `main` branch, which includes MatMaul's wake lock changes. Install: 1. Download the .apk file and install it. Note that this will upgrade the internal database schema of the ntfy App, meaning that you cannot go back to the prod version **without losing subscriptions and notifications.** 2. Go to Settings -> Toggle "Persistent wakelock" to OFF ## adb 1. Turn on developer mode on your phone: Go to "Settings", then tap "About device" or "About phone". Scroll down, then tap "Build number" seven times. 2. Go to Settings -> System -> Developer options, Turn ON "Wireless ADB debugging" and "Wireless debugging" (you may have to repeat this step every time you reconnect to the wifi) 3. Install the Android Sdk, then run `adb connect <yourphoneip>`. It could say "connected" after you ACK it on your phone 4. Then you should be able to do `adb logcat --pid=$(adb shell pidof -s io.heckel.ntfy)`
Author
Owner

@arminus commented on GitHub (Jan 12, 2022):

Install worked, adb logcat returns this (after some init stuff) approx every 30 seconds:

01-12 19:57:22.656 25455 25517 D NtfySubscriberConn: [http://pi4:8085/mytopics,ipad] Connection is active (failed=false, callCanceled=false, jobActive=true, serviceStarted=true
01-12 19:57:53.246 25455 25516 D NtfySubscriberConn: [http://pi4:8085/mytopics,ipad] Connection is active (failed=false, callCanceled=false, jobActive=true, serviceStarted=true
01-12 19:58:24.702 25455 25517 D NtfySubscriberConn: [http://pi4:8085/mytopics,ipad] Connection is active (failed=false, callCanceled=false, jobActive=true, serviceStarted=true

Full log is attached, I guess there's nothing more to be gained by keeping logcat running any longer?

Then I'll have more detail on the power consumption tomorrow

logcat.txt

<!-- gh-comment-id:1011360523 --> @arminus commented on GitHub (Jan 12, 2022): Install worked, adb logcat returns this (after some init stuff) approx every 30 seconds: ``` 01-12 19:57:22.656 25455 25517 D NtfySubscriberConn: [http://pi4:8085/mytopics,ipad] Connection is active (failed=false, callCanceled=false, jobActive=true, serviceStarted=true 01-12 19:57:53.246 25455 25516 D NtfySubscriberConn: [http://pi4:8085/mytopics,ipad] Connection is active (failed=false, callCanceled=false, jobActive=true, serviceStarted=true 01-12 19:58:24.702 25455 25517 D NtfySubscriberConn: [http://pi4:8085/mytopics,ipad] Connection is active (failed=false, callCanceled=false, jobActive=true, serviceStarted=true ``` Full log is attached, I guess there's nothing more to be gained by keeping logcat running any longer? Then I'll have more detail on the power consumption tomorrow [logcat.txt](https://github.com/binwiederhier/ntfy/files/7857031/logcat.txt)
Author
Owner

@binwiederhier commented on GitHub (Jan 12, 2022):

Yeah the log looks perfectly normal. We'd have to keep it running for a longer period of time if there are reconnects or something I think. Or get and excerpt from longer ago...

<!-- gh-comment-id:1011379477 --> @binwiederhier commented on GitHub (Jan 12, 2022): Yeah the log looks perfectly normal. We'd have to keep it running for a longer period of time if there are reconnects or something I think. Or get and excerpt from longer ago...
Author
Owner

@arminus commented on GitHub (Jan 12, 2022):

I'll keep you posted on the power stats of the new version.

<!-- gh-comment-id:1011385340 --> @arminus commented on GitHub (Jan 12, 2022): I'll keep you posted on the power stats of the new version.
Author
Owner

@arminus commented on GitHub (Jan 13, 2022):

Ok, today, ntfy doesn't event register on the battery monitor's app sucker page :-), i.e. no problem whatsoever with Persistent wakelock set to off.

So just being curious: Why would that wake lock need to be turned on? In my case (Android 8), I still get immediate notifications. Is that needed on newer Android version so as to not being killed by the OS? I might eventually have a newer phone, so just to be "future-proof" ;-)

<!-- gh-comment-id:1012069504 --> @arminus commented on GitHub (Jan 13, 2022): Ok, today, ntfy doesn't event register on the battery monitor's app sucker page :-), i.e. no problem whatsoever with Persistent wakelock set to off. So just being curious: Why would that wake lock need to be turned on? In my case (Android 8), I still get immediate notifications. Is that needed on newer Android version so as to not being killed by the OS? I might eventually have a newer phone, so just to be "future-proof" ;-)
Author
Owner

@binwiederhier commented on GitHub (Jan 13, 2022):

Ok, today, ntfy doesn't event register on the battery monitor's app sucker page :-), i.e. no problem whatsoever with Persistent wakelock set to off.

That is awesome to hear, and mirrors my experience.

Why would that wake lock need to be turned on?

I get immediate notifications too, and I have a OnePlus phone which are notorious for killing apps. All of the docs say that Android can and will eventually kill apps that run in the background like this. But it doesn't. I don't know is the short answer. It seems contrary to the docs.

<!-- gh-comment-id:1012118553 --> @binwiederhier commented on GitHub (Jan 13, 2022): > Ok, today, ntfy doesn't event register on the battery monitor's app sucker page :-), i.e. no problem whatsoever with Persistent wakelock set to off. That is awesome to hear, and mirrors my experience. > Why would that wake lock need to be turned on? I get immediate notifications too, and I have a OnePlus phone which are notorious for killing apps. All of the docs say that Android can and will eventually kill apps that run in the background like this. But it doesn't. I don't know is the short answer. It seems contrary to the docs.
Author
Owner

@binwiederhier commented on GitHub (Jan 19, 2022):

I think I'm okay with what we have with JSON stream and websockets. Closing this.
Now that wakelock is not the default anymore.

<!-- gh-comment-id:1016038180 --> @binwiederhier commented on GitHub (Jan 19, 2022): I think I'm okay with what we have with JSON stream and websockets. Closing this. Now that wakelock is not the default anymore.
Author
Owner

@GitHubGeek commented on GitHub (Jan 20, 2022):

A quick thank you note to people involved. The battery saving upgrading from 1.5.2 to 1.6 (wakelock disabled) is amazing. Much appreciated!

<!-- gh-comment-id:1017090904 --> @GitHubGeek commented on GitHub (Jan 20, 2022): A quick *thank you* note to people involved. The battery saving upgrading from 1.5.2 to 1.6 (wakelock disabled) is amazing. Much appreciated!
Author
Owner

@binwiederhier commented on GitHub (Jan 20, 2022):

Much appreciated. It was all @MatMaul really, he deserves all the credit.

<!-- gh-comment-id:1017113751 --> @binwiederhier commented on GitHub (Jan 20, 2022): Much appreciated. It was all @MatMaul really, he deserves all the credit.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#61
No description provided.